/* Superstrider Simulator v. 1.1 Beta: Copyright 2018 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This software has been assigned SCR# 2200.0. This number is a Sandia internal tracking number and is a useful reference when contacting the Legal Technology Transfer Center or Licensing and IP Management. This software was originally assigned Export Control Classification Number (ECCN) EAR 99. However, since this software is to be released as OSS, the software is deemed to be Publicly Available. */ /* Note: This is the author's current copy of the program being released February 2, 2018 coincident with an update to the government-authorized copyright license. The author compiles the program with Microsoft Visual Studio 2005 and it seems to run the test code properly. The #define block below controls features. Code refinement for additional platform compatibility may be added later and will not require a new license. Description of the changes to functionality of in ver 1.1 Beta: (a) The simulator was changed from "functional" to a model representing a hardware design. (b) The simulated hardware includes a table-driven control language. (c) The arithmetic unit was changed from software "loops" to simulation of a hardware structure called a sorting network. */ #define SNCODE 0 // 1: enable sorting network code, else 0 #define SORTOPTION 0 // 0: regular 1: reverse 2: random #define READDVEC 0 // 1: loop addvec leaf addition, else 0 #define RANGEINHTML 0 // 1: put row key range in html printouts (expands printout to two lines per row), else 0 #define DISABLENMOPTIMIZATION 0 // 1: normalize runs max and min on both sides whether needed or not #define MATMARKET 2 // 0: random 1: read from matrix market files 2: 3x4 test matrix #define BIG 2 // size of default test #define EXPLAIN 0 // 1: put explanations of symbols in HTML, else 0 #define SEQVERTMODE 0 // 1: print command sequences vertically, else horizontally #define YTRANSPOSE 0 // 1: second operation transposes Z to Y 1: just copies int MMTRACE = 0; // trace matrix multiply #define MMS 10000 // first matrix multiply to print #define MME 10200 // last matrix multiply to print #define MATPRT 1 // print matrix generation int NormStrategy; // related to a normalization strategy to go all green or red first #define ROOTS 6 // now many reserved spaces for tree roots #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include #include #include #include #include #include #include using namespace std; #if __GNUC__ == 0 #pragma warning(disable : 4996) #include #include #include #else // compile with g++ Superstrider.cpp -lpthread // on Windows 10 do sudo bash first, so you can access the internet #include #include #include #include #include #include #include #include #include #define SOCKET int #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define stricmp(a, b) strcasecmp(a, b) #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #define BYTE unsigned char #define DWORD unsigned long #define WORD unsigned short #define __stdcall typedef struct RGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; #define isdigit(c) ((c) >= '0' && (c) <= '9') #define isalpha(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') #define iscsym(c) (isdigit(c) || isalpha(c) || (c) == '_') #define _finite(f) isfinite(f) // Jeanine changed to isfinite(). Apparently finite() has been deprecated since osx 10.9 // see https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html long InterlockedExchange(long *ptr, long val) { __atomic_exchange_n(ptr, val, __ATOMIC_RELAXED); } long InterlockedExchangeAdd(long *ptr, long val) { __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED); } long InterlockedIncrement(long *ptr) { return __atomic_fetch_add(ptr, 1L, __ATOMIC_RELAXED)+1; } #define _mkdir(s) mkdir(s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) #define closesocket close #define strnicmp strncasecmp #define Sleep(s) usleep(s*1000) #define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16))) int CloseHandle (pthread_t) { } // fixme typedef struct _FILETIME { unsigned long dwLowDateTime; unsigned long dwHighDateTime; } FILETIME, *PFILETIME, *LPFILETIME; #define FileTimeToSystemTime(a, b) #define HANDLE int typedef union _LARGE_INTEGER { struct { unsigned long LowPart; long HighPart; }; struct { unsigned long LowPart; long HighPart; } u; } LARGE_INTEGER; unsigned long WaitForSingleObject(pthread_t hHandle, int dwMilliseconds) { } #define STILL_ACTIVE 1 #define SYSTEMTIME int #define SOCKADDR_IN sockaddr_in #define _CrtCheckMemory() #define WSACleanup() #define _CrtDumpMemoryLeaks() #endif // } // modes area #define STATS 0 // 1 to enable statistics #define BITSMODE 0 // 0->int64, 1->long, 2->2 unsigned longs (mode 1 won't work) #define INLINECOMPLEX 0 // 1 for inline implementation of complex numbers; 0 for debugging #define USEGIF 1 // define either of these to be nonzero to generate output in the appropriate graphics format #define USEBMP 0 #define COMMANDS 5 #define MACHINES 5 #define PERFECTION 2 #define NUMPLOTS (COMMANDS+4+7) #define APPPLOT COMMANDS #define MFPLOT1 (COMMANDS+1) #define MFPLOT2 (COMMANDS+2) #define MFPLOT3 (COMMANDS+3) #define PLOTFACTOR 10 #define FANCYPAGE 1 // set to 1 to include fancypage formatting #define SAMPLECOMMANDS 0 // set to 1 to include sample commands enum eDataValidity { // system can accommodate real and extrapolated points Ephemeral=0, Real=1, }; const char *Out1 = ""; const char *Out2 = ""; const char *NOut1 = ""; const char *NOut2 = ""; const char *NO1 = ""; const char *NO2 = ""; class DataPoint { public: double X, Y; char *Text; }; class HTMLGraph { int NumPoints, MaxPoints; DataPoint *Data; int color; // color of the "real" lines in a graph int bgcolor; // color of "unreal" lines, or projected values. If -1 then no line drawn void *payload; double minx, maxx, miny, maxy; int width, height; public: enum xxeDataValidity { // system can accommodate real and extrapolated points Ephemeral=0, Real=1, }; enum eDataMark { // should data points be marked with a cross or box? NoMark=0, Square=1, NoLineNoMark=2, NoLineSquare=3, }; enum eSpecMinX { // minimum X value in chart CalcMinX=0, SpecMinX=1, }; enum eSpecMaxX { // maxiumum X value in chart CalcMaxX=0, SpecMaxX=1, }; enum eSpecMinY { // minimum Y value in chart CalcMinY=0, SpecMinY=1, }; enum eSpecMaxY { // maximum Y value in chart CalcMaxY=0, SpecMaxY=1, }; HTMLGraph(); void SetName(int c, int bgc); void Clear(); ~HTMLGraph(); void AddPoint(double d, double t, char *tx, void *p, eDataValidity real); void WriteToBitmap(int **image, int logx, int logy, double ix, double ax, double iy, double ay, int ii, int jj, HTMLGraph::eDataMark cross); void Range(double &minx, double &maxx, double &miny, double &maxy) ; int backtranslate(FILE *output, int x, int y, int dist); friend void HTMLGraph_Print(FILE *output, const char *title, int n, int logx, int fmtx, int logy, int fmty_unused, HTMLGraph *dope, int *Color, int bgcolor, HTMLGraph::eDataMark cross, HTMLGraph::eSpecMinX fixminx, double aminx, HTMLGraph::eSpecMaxX fixmaxx, double amaxx, HTMLGraph::eSpecMinY fixminy, double aminy, HTMLGraph::eSpecMaxY fixmaxy, double amaxy); }; // print a data set as an HTML included graphic // can optionally print multiple traphs for comparison // scaling can be specified for { min, max } { x, y } where each combination can be fixed or an extremum5 value can be specified void HTMLGraph_Print(FILE *output, const char *title, int n, int logx, int fmtx, int logy, int fmty_unused, HTMLGraph *dope, int *Color, int bgcolor, HTMLGraph::eDataMark cross, HTMLGraph::eSpecMinX fixminx = HTMLGraph::CalcMinX, double aminx = 1e100, HTMLGraph::eSpecMaxX fixmaxx = HTMLGraph::CalcMaxX, double amaxx = -1e100, HTMLGraph::eSpecMinY fixminy = HTMLGraph::CalcMinY, double aminy = 1e100, HTMLGraph::eSpecMaxY fixmaxy = HTMLGraph::CalcMaxY, double amaxy = -1e100) ; // This is a buffer for bitmap images to be rendered semi-independently of pages // It has some accommodation to multi-threading // The MIME pointer is atomically set to non-NULL when the file has been fully set up for serving // Variable BuffersTop is atomically set to the number of cells to check, except it should be clipped to IMAGESTORELIMIT-1 // I think there could be a timing bug when the image store is cleared, but this is not done except at program exit #define IMAGESTORELIMIT 1000 extern struct ImageStore { char Name[50]; // this will be the pathname for access, as in http://127.0.0.1/bm0.bmp int Len; // length of the image file (below) const char *MIME; // MIME type of data (NOT allocated from storage pool) char *Dope; } Buffer[IMAGESTORELIMIT]; extern long BuffersTop; // atomic increment extern int ImageStoreSearch(char *n); // find a file extern void ImageStoreClear(); // reset (may not be timing stable) extern FILE *ArchiveFile(const char *notation, const char *extension, int link, char *stash); extern HTMLGraph PlotData[NUMPLOTS]; extern void Plotfcn(void *base, double amp, double horiz, eDataValidity real); // image buffer capability #define IMAGESTORELIMIT 1000 extern class IStore { public: struct { char Name[50]; // this will be the pathname for access, as in http://127.0.0.1/bm0.bmp int Len; // length of the image file (below) const char *MIME; // MIME type of data (NOT allocated from storage pool) char *Dope; } Buffer[IMAGESTORELIMIT]; long BuffersTop; // atomic increment int ImageStoreSearch(char *n); void ImageStoreClear(); FILE *ArchiveFile(const char *notation, const char *extension, int link, char *stash); } ImageStore; // this is a class with a web browser query and a socket with which to respond to it #define SENDBUFSZ 512 class ServeData { friend int main(int argc, char* argv[]); char *URI; // file name relative to this server FILE *index; // place to send data char *p; // input buffer int lastwrite; // next position to write (for incremental output) unsigned int theClient; // socket for output public: int argc; // number of arguments char **name; // pointer to array of asciz names created by malloc/malloc char **value; // pointer to array of asciz values created by malloc/malloc ServeData() { } ServeData(ServeData *s) { *this = *s; } void Set(unsigned int s); void FreeUp(); void CloseAndFreeUp(); void Serve404(); void Serve200(); void TitleTextNoDiskBackup(char *title); FILE *TitleTextOpenBufferFile(const char *title, const char *notation, const char *extension, int link, char *stash, int reload = -1); void IncrementalWrite(); void CloseBufferFile(); void BasicServe(const char *title, const char *msg); // unused virtuals an anticipation of the need to parse the browser-supplied input char *URLDecode(char *x); void SD(double &d, char *v); void SI(int &n, char *v); void SS(char *&p, char *v); void SB(int &b, char *v) ; }; // local thread manager // NOTE: Does not include the main thread #define MAXTHREADS 100 class cThreads { public: // initialize data structure -- like a creator function virtual void Initialize() { }; // launch a thread, putting a reference to it in local storage virtual void Add(void (__stdcall *f) (ServeData *), ServeData *p) { }; // print system status virtual void Print(FILE *fd, int html) { }; // close everything, waiting until active threads terminate virtual void AllDone() { }; }; extern cThreads *Threads; // Assertion support #define ASSERTALWAYS(c) if (!(c)) { fprintf(stderr, "assert failed"); fflush(stderr); botchassert(); } #undef ASSERT #define FPASSERT(a, b) if ((a)/(b) < .9999 || (a)/(b) > 1.0001) { fprintf(stderr, "FP assert failed"); fflush(stderr); botchassert(); } #define ASSERT(x) if (!(x)) asserterror(#x); void botchassert() { double pi=3.14; } void asserterror(const char *msg) { printf("assert error %s\n", msg); getchar(); } #if __GNUC__ == 0 // see https://en.wikipedia.org/wiki/Linear_congruential_generator for constants // The linear congruential generator is mod 2^64, but only 31 bits are used // the constants are used in "Newlib, Musl" -- whatever they are ULARGE_INTEGER myrandstate = { 123, }; #define MYRANDMAX 0x7fffffff static int myrand() { myrandstate.QuadPart = 6364136223846793005ULL*myrandstate.QuadPart + 1ULL; int rval = myrandstate.HighPart & MYRANDMAX; return rval; } static void mysrand(int s) { myrandstate.QuadPart = s; } #else static unsigned myrandstate = 123; #define MYRANDMAX 0x7fff static int myrand() { int rval = (myrandstate = 214013L*myrandstate + 2531011L); return (rval >> 16)&MYRANDMAX; } static void mysrand(int s) { srand(s); myrandstate = s; } #endif // Print a floating number with the SI suffix, as in 10.4ns // Returns a ASCIZ string from a rotating static buffer (generally sufficient for printf) // Second argument is the number of significant digits, defaulting to three // Third argument controls weather the micro suffix will be a Roman "u" or an // HTML [ISO 8859-1 (Latin-1) Entities] micro sign µ // Fourth argument controlls the power that will be applied to the SI prefix; // Pwr=2 causes m to mean 10**-6 instead of 10**-3, as in // a square inch is .000645m^2 or 645mm^2. char *SISuffix(double x, int digits = 3, int html = 1, int pwr = 1) { static char dope[20][50]; static int next = 0; static struct g { double limit; int basedigits; const char *suffix; double divide; } table[] = { { 1e-23, 2, "y", 1e-24, }, { 1e-22, 1, "y", 1e-24, }, { 1e-21, 0, "y", 1e-24, }, { 1e-20, 2, "z", 1e-21, }, { 1e-19, 1, "z", 1e-21, }, { 1e-18, 0, "z", 1e-21, }, { 1e-17, 2, "a", 1e-18, }, { 1e-16, 1, "a", 1e-18, }, { 1e-15, 0, "a", 1e-18, }, { 1e-14, 2, "f", 1e-15, }, { 1e-13, 1, "f", 1e-15, }, { 1e-12, 0, "f", 1e-15, }, { 1e-11, 2, "p", 1e-12, }, { 1e-10, 1, "p", 1e-12, }, { 1e-9, 0, "p", 1e-12, }, { 1e-8, 2, "n", 1e-9, }, { 1e-7, 1, "n", 1e-9, }, { 1e-6, 0, "n", 1e-9, }, { 1e-5, 2, "u", 1e-6, }, { 1e-4, 1, "u", 1e-6, }, { 1e-3, 0, "u", 1e-6, }, { 1e-2, 2, "m", 1e-3, }, { 1e-1, 1, "m", 1e-3, }, { 1e0, 0, "m", 1e-3, }, { 1e1, 2, "", 1, }, { 1e2, 1, "", 1, }, { 1e3, 0, "", 1, }, { 1e4, 2, "K", 1e3, }, { 1e5, 1, "K", 1e3, }, { 1e6, 0, "K", 1e3, }, { 1e7, 2, "M", 1e6, }, { 1e8, 1, "M", 1e6, }, { 1e9, 0, "M", 1e6, }, { 1e10, 2, "G", 1e9, }, { 1e11, 1, "G", 1e9, }, { 1e12, 0, "G", 1e9, }, { 1e13, 2, "T", 1e12, }, { 1e14, 1, "T", 1e12, }, { 1e15, 0, "T", 1e12, }, { 1e16, 2, "P", 1e15, }, { 1e17, 1, "P", 1e15, }, { 1e18, 0, "P", 1e15, }, { 1e19, 2, "E", 1e18, }, { 1e20, 1, "E", 1e18, }, { 1e21, 0, "E", 1e18, }, { 1e22, 2, "Z", 1e21, }, { 1e23, 1, "Z", 1e21, }, { 1e24, 0, "Z", 1e21, }, { 1e25, 2, "Y", 1e24, }, { 1e26, 1, "Y", 1e24, }, { 1e27, 0, "Y", 1e24, }, }; char format[50]; char *p = dope[next%20]; // handle negatives if (x < 0) { x = -x; *p++ = '-'; } // zero has only one representation -- "0" if (x == 0) { sprintf(dope[next%20], "0"); return dope[next++%20]; } // numbers between .1 and 1 can be represented with a leading decimal, as in .1, .2, .2004 else if (x >= .1 && x < 1) { // sprintf(p, ".%.0f", x*pow(10, digits)); sprintf(p, "%.*f", digits, x); for (int i = strlen(p); --i > 1 && p[i] == '0'; ) p[i] = 0; return dope[next++%20]; } // other numbers to be represented by a number n, 1 <= n <= 999.999 if (x >= 1e-26) for (unsigned int i = 0; i < sizeof(table)/sizeof(g); i++) { double limit = table[i].limit, divide = table[i].divide; if (1) for (int j = 1; j < pwr; j++) { limit *= table[i].limit; divide *= table[i].divide; } if (x < limit) { const char *s = table[i].suffix; if (s[0] == 'u' && html) s = "µ"; int d = table[i].basedigits + digits - 3; if (d < 0) d = 0; sprintf(format, "%%.%dlf", d); sprintf(p, format, x/divide); // now suppress trailing zeros if (d > 0) { int j; for (j = strlen(p); --j >= 1 && p[j] == '0'; ) p[j] = 0; if (p[j = strlen(p)-1] == '.') p[j] = 0; } strcat(p, s); // add suffix return dope[next++%20]; } } sprintf(format, "%%.%dle", digits-1); sprintf(p, format, x); return dope[next++%20]; } char *SISuffix2(double x, int digits = 3, int html = 1) { return SISuffix(x, digits, html, 2); } char *SISuffixC(double re, double im, int digits = 3, int html = 1, int pwr = 1) { static char dope[20][103]; static int next = 0; char *p = dope[next%20]; *p = 0; //sprintf(p, "%.4f+%.4fi", re, im); //return p; const char *rt = SISuffix(re, digits, html, pwr); const char *it = SISuffix(im, digits, html, pwr); // sprintf(p, "(%.4f, %.4f, %s, %s)", re, im, rt, it); // return p; if (im == 0) sprintf(p, "(%s)", rt); else if (re == 0) sprintf(p, "(%si)", it); else if (im > 0) sprintf(p, "(%s+%si)", rt, it); else sprintf(p, "(%s%si)", rt, it); return p; } double SIRound(double v) { double t; static double table[] = { 1, 1.5, 2, 3, 5, 7, 9, }; for (int e = 100; --e >= -100;) for (int f = 7; --f >= 0;) if ((t = table[f] * pow(10., e)) < v) return t; return 1.0; } #define MinPlot 1e-3 #define MaxPlot 1e22 #define SCALE 1 // 1 for small graphics; proportionately larger #define SUBDIVIDE 4 // oversample each pixel this many times in x and y #define GRAPHPOINTS ((int)(600*SCALE)) #define GRAPHHEIGHT ((int)(300*SCALE)) #define GRAPHWIDTH ((int)(2*SCALE)) #define PICTUREPOINTS ((int)(350*SCALE)) #define PICTUREHEIGHT ((int)(250*SCALE)) #define PICTUREWIDTH ((int)(2*SCALE)) #define SQUARESIZE ((int)(2*SCALE)) #define SEGHT ((int)(4*SCALE)) // "7 segment" line height (1/2 character height) #define SEGWD ((int)(3*SCALE)) // "7 segment" line width #define SEGSP ((int)(5*SCALE)) // character spacing #define SEGLW ((int)(1+SCALE/3)) // width of drawing line #define VMAR ((int)(10*SCALE)) // graph vertical margin (at bottom) for axis #define HMAR ((int)(27*SCALE)) // graph horizontal margin (at left) for axis // Allocate an archival disk file, returning an open FILE * for writing its contents // If link == 1, create a hyperlink to this file from archive.htm // If stash != NULL, store the (relative) file name FILE *ArchiveFile(const char *notation, const char *extension, int link, char *stash) { time_t long_time; time(&long_time); // additional segment char fraction[10]; fraction[0] = 0; for (int i = 0; i < 50; i++) { struct tm *newtime = localtime(&long_time); const char *mon[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", }; char fn[200], fn2[200]; sprintf(fn, "%s-%02d%s%02d-%02dh%02dm%02ds%s.%s", notation, newtime->tm_mday, mon[newtime->tm_mon], newtime->tm_year-100, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, fraction, extension); sprintf(fn2, "archive/%s", fn); if (stash != NULL) sprintf(stash, "%s", fn); // create the directory _mkdir("archive"); // see if the file exists FILE *rval = fopen(fn2, "r"); // doesn't exist, see if we can make it if (rval == NULL) { rval = fopen(fn2, "wb+"); //fclose(rval); //rval = fopen(fn2, "wb+"); } // oops, exists, close it and try another else { fclose(rval); rval = NULL; } // got one if (rval != NULL) { if (link != 0) { FILE *ff = fopen("archive.htm", "a"); fprintf(ff, "%s
\n", fn, fn); fclose(ff); } return rval; } sprintf(fraction, ".%02x", unsigned(myrand()&0xff)); } ASSERTALWAYS(0); return NULL; } // clear buffers // atomically destroy the MIME type pointer to indicate unavailable // then atomically set the BuffersTop pointer to permit reuse void ImageStoreClear() { for (int i = 0; i < IMAGESTORELIMIT; i++) { InterlockedExchange((long *)&ImageStore.Buffer[i].MIME, 0); ImageStore.Buffer[i].Name[0] = 0; ImageStore.Buffer[i].Len = 0; #define IMAGESTOREPOINTER 1 #if IMAGESTOREPOINTER != 0 delete ImageStore.Buffer[i].Dope; #endif } InterlockedExchange(&ImageStore.BuffersTop, 0); } // search image store for an image matching the url int ImageStoreSearch(char *n) { for (int i = 0, e = InterlockedExchangeAdd(&ImageStore.BuffersTop, 0); i < e; i++) { if (i >= IMAGESTORELIMIT) break; if (InterlockedExchangeAdd((long *)&ImageStore.Buffer[i].MIME, 0) != 0) if (strcmp(ImageStore.Buffer[i].Name, n) == 0) return i; } return -1; } void Dither(int x, int y, int **image, int lvr, int lvg, int lvb) { unsigned char maptabr[256], maptabg[256], maptabb[256]; if (1) for (int i = 0; i < 256; i++) { maptabr[i] = (i+255/2/lvr) * lvr / 255 * 255 / lvr; maptabg[i] = (i+255/2/lvg) * lvg / 255 * 255 / lvg; maptabb[i] = (i+255/2/lvb) * lvb / 255 * 255 / lvb; } if (1) for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { int c = image[i][j]; // get the color unsigned char cr = c>>16; unsigned char cg = c>>8; unsigned char cb = c; unsigned char nr = maptabr[cr]; // cut the range unsigned char ng = maptabg[cg]; unsigned char nb = maptabb[cb]; image[i][j] = nr<<16 | ng<<8 | nb; char er = cr - nr; // the error char eg = cg - ng; char eb = cb - nb; unsigned long rn = myrand(); for (int n = 0; n < 15; n++) { int ii = i, jj = j; switch (n&3) { case 0: jj++; break; case 1: ii++; break; case 2: ii++; jj--; break; case 3: ii++; jj++; break; } if (ii < 0 || ii >= x || jj < 0 || jj >= y) continue; if ((rn & 1<>16; cg = c>>8; cb = c; if (er != 0) nr = min(255, max(0, cr + (er>>2|1))), er -= nr - cr; else nr = cr; if (eg != 0) ng = min(255, max(0, cg + (eg>>2|1))), eg -= ng - cg; else ng = cg; if (eb != 0) nb = min(255, max(0, cb + (eb>>2|1))), eb -= nb - cb; else nb = cb; image[ii][jj] = nr<<16 | ng<<8 | nb; if (er == 0 && eg == 0 && eb == 0) break; } } } } // add an image to the store char *ImageStoreAdd(int x, int y, int **image) { int i = InterlockedIncrement(&ImageStore.BuffersTop); if (--i >= IMAGESTORELIMIT) return NULL; FILE *f = ArchiveFile("image", "bmp", 0, ImageStore.Buffer[i].Name); int bytes_per_line=(x*24+31)/32*4; ImageStore.Buffer[i].Len = 54 + bytes_per_line * y; char *p = (char *)malloc(ImageStore.Buffer[i].Len); ImageStore.Buffer[i].Dope = p; *p++ = 'B'; *p++ = 'M'; *(*(long **)&p)++ = 14+40; // file size *(*(short **)&p)++ = 0; // reserved *(*(short **)&p)++ = 0; // reserved *(*(long **)&p)++ = 14+40; // offset bits *(*(long **)&p)++ = 40; // size *(*(long **)&p)++ = x; // width *(*(long **)&p)++ = y; // height *(*(short **)&p)++ = 1; // planes *(*(short **)&p)++ = 24; // bit count *(*(long **)&p)++ = 0; // compression *(*(long **)&p)++ = bytes_per_line*y;// image size *(*(long **)&p)++ = 75*39; // x_pixels *(*(long **)&p)++ = 75*39; // y_pixels *(*(long **)&p)++ = 0; // number colors *(*(long **)&p)++ = 0; // colors important if (1) for (int j = 0; j < y; j++) { if (1) for (int i = 0; i < x; i++) { *p++ = image[i][j]; *p++ = image[i][j]>>8; *p++ = image[i][j]>>16; } if (1) for (int i = x*3; i < bytes_per_line; i++) *p++ = 0; } fwrite(ImageStore.Buffer[i].Dope, 1, ImageStore.Buffer[i].Len, f); fclose(f); const char *mime = "image/bmp"; InterlockedExchange((long *)&ImageStore.Buffer[i].MIME, (long)mime); return ImageStore.Buffer[i].Name; } // begin GIF Code #define LEVR 6 // number of levels of red in 256 color palette #define LEVG 6 // number of levels of green in 256 color palette #define LEVB 6 // number of levels of blue in 256 color palette void Putword(int w, FILE *f) { fputc(w, f); fputc(w>>8, f); } void EncodeHeader(int x, int y, RGBQUAD *pPal, FILE *f) { int Colors = 256; // number of colors fwrite("GIF89a", 1, 6, f); // GIF Header Putword(x, f); // logical screen width Putword(y, f); // logical screen height unsigned char field; // Packed fields if (Colors == 0) field=0x11; else { field = 0x80; // global color table flag field |= 7 << 5; // color resolution field |= 7; // size of global color table } fputc(field, f); // Packed fields fputc(0, f); // Background color index fputc(0, f); // Pixel aspect ratio if (Colors != 0) for (int i = 0; i < Colors; i++) { fputc(pPal[i].rgbRed, f); fputc(pPal[i].rgbGreen, f); fputc(pPal[i].rgbBlue, f); } } void EncodeExtension(int delay, FILE *f) { fputc('!', f); // extension introducer fputc(0xF9, f); // graphic control label struct anonymous_structure { // 4 bytes unsigned char transpcolflag:1; unsigned char userinputflag:1; unsigned char dispmeth:3; unsigned char res:3; unsigned char delaylow; unsigned char delayhigh; unsigned char transpcolindex; } gg; gg.transpcolflag = 0; gg.userinputflag = 0; gg.dispmeth = 0; gg.res = 0; gg.delaylow = (unsigned)delay; gg.delayhigh = (unsigned)(delay)>>8; gg.transpcolindex = -1; fputc(sizeof(gg), f); // block size (4) fwrite(&gg, sizeof(gg), 1, f); // packed fields fputc(0, f); // block terminator } void EncodeLoopExtension(int n, FILE *f) { fputc('!', f); // Extension introducer fputc(255, f); // Extension label fputc(11, f); // Block size fwrite("NETSCAPE2.0", 11, 1, f); fputc(3, f); // Block size fputc(1, f); // App-dependent code? Putword(min(65536, n), f); // Loop length fputc(0, f); // Block terminator } void EncodeComment(const char *comment, FILE *f) { int len = strlen(comment); if (len > 255) len = 255; if (len) { fputc('!', f); // Extension introducer fputc(254, f); // Comment label fputc(len, f); // Size of comment fwrite(comment, len, 1, f); // Comment data fputc(0, f); // Block terminator } } class GIFEncoderState { #define BUFMAX 255 // can be as large as 255 class BitOut { unsigned int Acc; // bit accumulator for bit-oriented encoding format int Bits; // number of bits valid in Acc int CodeSize; // number of bits/code class BufGif { char Buffer[BUFMAX]; // output buffer int Count; // number of pending characters in output buffer FILE *Out; // write output here public: BufGif(FILE *f) { Count = 0; Out = f; // save pointer to output file } // transmit contents of the output buffer void Flush() { if (Count > 0) { fputc(Count, Out); // GIF format block size fwrite(Buffer, 1, Count, Out); // block of size just specified Count = 0; } } void Output(int Chr) { Buffer[Count++] = Chr; // output a character if (Count >= BUFMAX) // transmit buffer as a (cnt, buffer) block as needed Flush(); } ~BufGif() { Flush(); fflush(Out); // fflush for good measure } } GifBlk; public: // Set up the necessary values BitOut(FILE *f): GifBlk(f) { Acc = 0; Bits = 0; CodeSize = 9; } // Accept the supplied code for output in bit mode, // buffering up to 7 bits of an incomplete byte. // Initially output 9 bit bytes, but increase this // when the caller specifies that the max possible // code exceeds the largest representable code. // Request to output code 257 only occurs as the // last character of the transmission sequence and // can be used as an indication to flush pending bits. void Output(int Code, int FreeCode, int ClearFlag) { Acc |= Code << Bits; // add to accumulator (high bits will be zero) Bits += CodeSize; while (Bits >= 8) { // transmit 8 bits at a time until less than 8 stored GifBlk.Output(Acc); Acc >>= 8; Bits -= 8; } if (ClearFlag) // resetting block at 9 bit codes CodeSize = 9; else if (CodeSize < 12 && FreeCode >= 1< 0) { // transmit 8 bits at a time until all gone GifBlk.Output(Acc); Acc >>= 8; Bits -= 8; } } } }; // Content addressible memory for (prefix, character) ordered pairs. // The entries in the CAM will be numbered 258..4095. // Function Lookup seeks to translate a (prefix, character) pair to an index. // If a lookup fails, it saves the arguments for a subsequent call to EnterLast. // EnterLast assigns the next code to the ordered pair, unless the CAM is // full. In this case, EnterLast returns 0. // FreeEntry is an official export: it is the number of the first unassigned code. // Uses an unbalanced tree, but scrambles order based on discussion in Knuth 6.4 p. 509 class HashTable { map SymTab; int KeySave; public: int FreeEntry; HashTable() { FreeEntry = 258; SymTab.clear(); } int Lookup(int Prefix, int Ch) { KeySave = Prefix<<8|Ch; map::iterator it = SymTab.find(KeySave); if (it != SymTab.end()) return it->second; return -1; } int EnterLast() { if (FreeEntry < 4096) { SymTab[KeySave] = FreeEntry++; return 1; } FreeEntry = 258; SymTab.clear(); return 0; } }; long CountDown; // raster scan of image // Get the next sequential pixel from the image // Does not dither, but reduces to a multi-level 256 color palete int GifNextPixel(int x, int y, int **image) { if (CountDown == 0) return EOF; CountDown--; int rgb = image[x - 1 - CountDown%x][CountDown/x]; unsigned char r = rgb>>16; unsigned char g = rgb>>8; unsigned char b = rgb; return (r * (LEVR-1) / 255)*LEVG*LEVB + (g * (LEVG-1) / 255)*LEVB + (b * (LEVB-1) / 255); } // LZW conpression void compressLZW(int x, int y, int **image, FILE *f) { HashTable Table; BitOut B(f); B.Output(256, Table.FreeEntry, 1); int Prefix = GifNextPixel(x, y, image), Ch; while ((Ch = GifNextPixel(x, y, image)) != EOF) { int Symbol = Table.Lookup(Prefix, Ch); if (Symbol >= 0) Prefix = Symbol; else { B.Output(Prefix, Table.FreeEntry, 0); Prefix = Ch; if (!Table.EnterLast()) B.Output(256, Table.FreeEntry, 1); } } B.Output(Prefix, Table.FreeEntry, 0); B.Output(257, Table.FreeEntry, 0); } public: void EncodeBody(int x, int y, int **image, FILE *f) { CountDown = (long)x * (long)y; fputc(',', f); Putword(0, f); Putword(0, f); Putword(x, f); Putword(y, f); fputc(0, f); // flags fputc(8, f); // initial code size compressLZW(x, y, image, f); fputc(0, f); // zero length packet signals end } GIFEncoderState() { } }; void EncodeGIF(int x, int y, int ***image, int numimage, RGBQUAD *pPal, const char *Comment, FILE *f) { GIFEncoderState es; EncodeHeader(x, y, pPal, f); if (numimage > 1) { EncodeLoopExtension(100000, f); for (int i = 0; i < numimage; i++) { EncodeExtension(50, f); es.EncodeBody(x, y, image[i], f); } } else { EncodeExtension(0, f); es.EncodeBody(x, y, image[0], f); } EncodeComment(Comment, f); fputc(';', f); } // add a GIF image to the store // for compatibility with old version, pass a pointer to the image array and count one char *GifImageStoreAdd(int x, int y, int ***image, int numimage = 1) { int bi = InterlockedIncrement(&ImageStore.BuffersTop); if (--bi >= IMAGESTORELIMIT) return NULL; if (1) for (int i = 0; i < numimage; i++) Dither(x, y, image[i], LEVR, LEVG, LEVB); FILE *f = ArchiveFile("image", "gif", 0, ImageStore.Buffer[bi].Name); // Synthesize a 256 (or less) color palette with some number of levels in each of rgb // The standard Internet palette has 6 levels in each color -- for a total of 216 colors RGBQUAD Pal[256]; { RGBQUAD rgb; rgb.rgbRed = 0; rgb.rgbGreen = 0; rgb.rgbBlue = 0; rgb.rgbReserved = 0; for (int i = 0; i < 255; i++) Pal[i] = rgb; for (int r = 0; r < LEVR; r++) for (int g = 0; g < LEVG; g++) for (int b = 0; b < LEVB; b++) { rgb.rgbRed = r * 255 / (LEVR-1); rgb.rgbGreen = g * 255 / (LEVG-1); rgb.rgbBlue = b * 255 / (LEVB-1); rgb.rgbReserved = 0; Pal[r*LEVG*LEVB + g*LEVB + b] = rgb; } } { EncodeGIF(x, y, image, numimage, Pal, "EPD Framework", f); fclose(f); char buf[200]; sprintf(buf, "archive/%s", ImageStore.Buffer[bi].Name); f = fopen(buf, "rb"); fseek(f, 0, SEEK_END); int len = ftell(f); ImageStore.Buffer[bi].Dope = (char *)malloc(5000+(ImageStore.Buffer[bi].Len = len)); fseek(f, 0, SEEK_SET); fread(ImageStore.Buffer[bi].Dope, 1, len, f); } fclose(f); const char *mime = "image/gif"; char *foo = (char *)InterlockedExchange((long *)&ImageStore.Buffer[bi].MIME, (long)mime); return ImageStore.Buffer[bi].Name; } // end GIF code void PolygonWrite(int **image, int maxi, int maxj, double *polygon, int npts, int color) { double *dope = new double[npts + 1000]; int nn; for (int i = 0; i < maxi; i++) { nn = 0; for (int n = 0; n < npts; n++) { double *p1 = &polygon[2*n]; double *p2 = &polygon[2*(n != npts-1 ? n+1 : 0)]; // skip if no intersection if (i < p1[0] && i < p2[0]) continue; if (i > p1[0] && i > p2[0]) continue; // skip if parallel to scan line if (p1[0] == p2[0]) continue; // skip top vertex if (p1[0] > p2[0] && i == p1[0]) continue; if (p1[0] < p2[0] && i == p2[0]) continue; // compute intersection double frac = (i-p1[0])/(p2[0]-p1[0]); double intersec = p1[1] + frac*(p2[1]-p1[1]); dope[nn++] = intersec; } // sort if (1) for (int ii = 0; ii < nn-1; ii++) { for (int jj = ii+1; jj < nn; jj++) if (dope[ii] > dope[jj]) { double t = dope[ii]; dope[ii] = dope[jj]; dope[jj] = t; } } // write if (1) for (int ii = 0; ii < nn; ii+=2) if (dope[ii] != dope[ii+1]) { int start = 5000 - (int)(5000.-dope[ii]); int end = 5000 - (int)(5000.-dope[ii+1]); while (start != end) { if (start >= 0 && start < maxj) image[i][start] = color; start++; } } } delete dope; } // write a line with a color, width, and possibly rounded ends // argument pts is the number of verticies at the end // pts == 2 is a square end // pts == 5 has 45 degree turns void LineWrite(int **image, int maxi, int maxj, double x1, double y1, double x2, double y2, int color, int wid = GRAPHWIDTH, unsigned int pts = 7) { double poly[160], *p = poly; // control number of end segments -- permits static buffer allocation if (pts < 2) pts = 2; else if (pts > sizeof(poly)/sizeof(double)/2) pts = sizeof(poly)/sizeof(double)/2; // compute parameters of line double len = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (len == 0) return; double vecx = (x2-x1)/len*wid*.5; double vecy = (y2-y1)/len*wid*.5; if (1) for (unsigned int i = 0; i < pts; i++) { double theta = (-90. + 180.*i/(pts-1))/(180./3.141592653589793238); *p++ = x2 + cos(theta) * vecx - sin(theta) * vecy; *p++ = y2 + sin(theta) * vecx + cos(theta) * vecy; } if (1) for (unsigned int i = 0; i < pts; i++) { double theta = (90. + 180.*i/(pts-1))/(180./3.141592653589793238); *p++ = x1 + cos(theta) * vecx - sin(theta) * vecy; *p++ = y1 + sin(theta) * vecx + cos(theta) * vecy; } PolygonWrite(image, maxi, maxj, poly, pts*2, color); } void PolyLineWrite(int **image, int maxi, int maxj, double *polygon, int npts, int color, int wid = 1) { for (int i = 0; i < npts; i++) { int j = i+1 < npts ? i+1 : 0; LineWrite(image, maxi, maxj, polygon[2*i], polygon[2*i+1], polygon[2*j], polygon[2*j+1], color, wid); } } // Line drawing for characters: // ABCDE // FGHIJ // KLMNO // PQRST // UVWXY // -------------- baseline // 01234 // 56789 // Z -- Pen up void TextWrite(int **image, int maxi, int maxj, double x, double y, const char *txt, int color, double hj = .5, double vj = .5) { double v = SEGHT; double h = SEGWD; double sp = SEGSP; int w = SEGLW; x = x + 1 - (2 + strlen(txt)*sp) * hj; y = y + 1 - (2 + 2*v) * vj; for (; *txt != 0; txt++) { static const char *CharForm[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // ()*+'-./ "XRHD", "VRHB", "FTXPJXWC", "RHZLN", "MD", "KO", "VW", "VD", // 01234567 "BFPVXTJDBZUE", "GCWZVX", "FBDJPUY", "AEKNTXU", "AKOZDX", "EAKNTXU", "DCKPVXTNL", "AEV", // 89:;<=>? "BFLNJDBZLPVXTN", "VWOJDBFLMO", NULL, NULL, "EKY", "FJZPT", "AOU", NULL, // @ABCDEFG NULL, "UCYNL", "ADJNKNTXUA", "JDBFPVXT", "AUXTJDA", "EAUYZKM", "EAUZKM", "JDBFPVXTOM", // HIJKLMNO "AUKOEY", "BDZVXZWC", "PVWSDZCE", "AUZKLZMEZMY", "AUY", "UAWEY", "UAYE", "BDJTXVPFB", // PQRSTUVW "UADJNK", "SYZXTJDBFPVX", "UADJNKZMY", "JDBFLNTXVP", "AEZCW", "APVXTE", "AWE", "AUCYE", // XYZ "AYZUE", "AMEZMW", "AEUY", NULL, NULL, NULL, NULL, NULL, // `abcdefg NULL, "YTNMLPVXT", "AUZPVWXTNLP", "OLPVY", "EYZTNLPVXT", "PTNLPVX", "JDCFVZKM", "O482ZTNLPVXT", // hijklmno "AUZPLNTY", "WMZGI", "M260ZGI", "AUZPOZPY", "CW", "UKZPLRWRNTY", "KUZPLNTY", "LPVXTNL", // pqrstuvw "5KZPLNTXVP", "N84ZSMLPVWS", "KUZPLNT", "OLPTXU", "CWZLN", "KPVXTZYO", "KWO", "KVMXO", // xyz{|}~ "KYZUO", "KWZOW5", "KOUY", NULL, "WC", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; const char *pat = CharForm[*txt]; if (pat != NULL) { double oldh = x; double oldv = y; int suppress = 1; for (; *pat != 0; pat++) { int c = *pat; if (c >= 'A' && c <= 'Z') c += 0 - 'A'; else if (c >= '0' && c <= '9') c += 25 - '0'; double v = y + SEGHT*2 - (double)(c/5)*SEGHT/2; double h = x + (double)(c%5) * SEGWD/5; if (suppress <= 0) LineWrite(image, maxi, maxj, oldh, oldv, h, v, color, SEGLW); oldh = h; oldv = v; if (pat[1] == 'Z') suppress = 2; else suppress--; } } x += sp; } } static int CvtColor(const char *name, int def) { if (stricmp(name, "Red") == 0) return 255<<16 | 0<<8 | 0; else if (stricmp(name, "Green") == 0) return 0<<16 | 255<<8 | 0; else if (stricmp(name, "Blue") == 0) return 0<<16 | 0<<8 | 255; else if (stricmp(name, "Black") == 0) return 0<<16 | 0<<8 | 0; else if (stricmp(name, "Purple") == 0) return 255<<16 | 0<<8 | 255; else if (stricmp(name, "Gray") == 0) return 128<<16 | 128<<8 | 128; else if (stricmp(name, "Brown") == 0) return 128<<16 | 128<<8 | 64; return def; } inline int advance(char *&p, char *&e) { while (*e != 0 && !isalpha(*e)) e++; if (*e == 0) return 0; p = e; while (iscsym(*e)) e++; return 1; } int advancen(char *&p, char *&e) { while (*e != 0 && !isdigit(*e)) e++; if (*e == 0) return 0; p = e; while (isdigit(*e)) e++; return 1; } void WriteMark(int **image, int ii, int jj, double x, double y, int mode, int color) { // if (mode == 0) return; double square[8], size = SQUARESIZE; if (mode == 2) size *= 1.5; square[0] = x-size; square[1] = y-size; square[2] = x+size; square[3] = y-size; square[4] = x+size; square[5] = y+size; square[6] = x-size; square[7] = y+size; PolygonWrite(image, ii, jj, square, 4, color); } HTMLGraph::HTMLGraph() { NumPoints = MaxPoints = 0; Data = 0; } void HTMLGraph::SetName(int c, int bgc) { color = c; bgcolor = bgc; } void HTMLGraph::Clear() { NumPoints = MaxPoints = 0; if (Data != 0) delete Data; Data = 0; } HTMLGraph::~HTMLGraph() { Clear(); } void HTMLGraph::AddPoint(double d, double t, char *tx, void *p, eDataValidity real) { if (p != NULL) payload = p; ASSERTALWAYS(_finite(d) && _finite(t)); if (NumPoints == MaxPoints) { MaxPoints = NumPoints + 100 + NumPoints/5; DataPoint *old = Data; Data = new DataPoint[MaxPoints]; if (1) for (int i = 0; i < NumPoints; i++) Data[i] = old[i]; delete old; } Data[NumPoints].X = t; Data[NumPoints].Y = d; Data[NumPoints].Text = tx; *(char *)&Data[NumPoints].Y &= ~3; *(char *)&Data[NumPoints++].Y |= real & 3; } void HTMLGraph::WriteToBitmap(int **image, int logx, int logy, double ix, double ax, double iy, double ay, int ii, int jj, HTMLGraph::eDataMark cross) { minx = ix; maxx = ax; miny = iy; maxy = ay; width = ii; height = jj; for (int i = 0; i < NumPoints-1; i++) { double x1 = ((logx!=0?log10(Data[i].X):Data[i].X)-minx)*(ii-HMAR)/(maxx-minx) + HMAR; double y1 = ((logy!=0?log10(Data[i].Y):Data[i].Y)-miny)*(jj-VMAR)/(maxy-miny) + VMAR; double x2 = ((logx!=0?log10(Data[i+1].X):Data[i+1].X)-minx)*(ii-HMAR)/(maxx-minx) + HMAR; double y2 = ((logy!=0?log10(Data[i+1].Y):Data[i+1].Y)-miny)*(jj-VMAR)/(maxy-miny) + VMAR; int real1 = *(char *)&Data[i].Y & 3; int real2 = *(char *)&Data[i+1].Y & 3; unsigned char r = color>>16; unsigned char br = bgcolor>>16; unsigned char g = color>>8; unsigned char bg = bgcolor>>8; unsigned char b = color; unsigned char bb = bgcolor; r = (int)r*2/4 + (int)br*2/4; g = (int)g*2/4 + (int)bg*2/4; b = (int)b*2/4 + (int)bb*2/4; int othercolor = r<<16 | g<<8 | b; if (cross&2) ; else if (bgcolor < 0 && (!real1 || !real2)) ; else LineWrite(image, ii, jj, x1, y1, x2, y2, real1 && real2 ? color : othercolor, real1 && real2 ? GRAPHWIDTH : GRAPHWIDTH*2/3); if (cross&1) { WriteMark(image, ii, jj, x1, y1, real1, color); WriteMark(image, ii, jj, x2, y2, real2, color); } if (i == 0 && Data[0].Text != NULL) TextWrite(image, ii, jj, x1, y1, Data[0].Text, color); if (Data[i+1].Text != NULL) TextWrite(image, ii, jj, x2, y2, Data[i+1].Text, color, 0., 0.); } } void HTMLGraph::Range(double &minx, double &maxx, double &miny, double &maxy) { for (int i = 0; i < NumPoints; i++) { if (minx > Data[i].X) minx = Data[i].X; if (maxx < Data[i].X) maxx = Data[i].X; if (miny > Data[i].Y) miny = Data[i].Y; if (maxy < Data[i].Y) maxy = Data[i].Y; } } // print a data set as an HTML included graphic // can optionally print multiple traphs for comparison // scaling can be specified for { min, max } { x, y } where each combination can be fixed or an extremum5 value can be specified // 1 output --> File buffer for HTML stream // 2 title --> Caption // 3 n --> Number of plot lines // 4 logx x scale logarithmic // 5 fmtx 0 means x scale uses SISuffix 1 means x scale uses printf // 6 logy y scale logarithmic // 7 fmty 0 means y scale uses SISuffix 1 means y scale uses printf // 8 dope // 9 Color // 10 bgcolor // 11 cross // 12 13 minimum x calculation // 14 15 maximum x calculation // 16 17 minimum y calculation // 18 19 maximum y calculation void HTMLGraph_Print(FILE *output, const char *title, int n, int logx, int fmtx, int logy, int fmty_unused, HTMLGraph *dope, int *Color, int bgcolor, HTMLGraph::eDataMark cross, HTMLGraph::eSpecMinX fixminx, double aminx, HTMLGraph::eSpecMaxX fixmaxx, double amaxx, HTMLGraph::eSpecMinY fixminy, double aminy, HTMLGraph::eSpecMaxY fixmaxy, double amaxy) { int color1 = Color[0]; int color2 = (n > 1) ? Color[1] : 0; // calculate overall range of all data double minx = aminx, maxx = amaxx, miny = aminy, maxy = amaxy; if (1) for (int ii = 0; ii < n; ii++) dope[ii].Range(minx, maxx, miny, maxy); // provide an overrun margin in the event of automatic dimensions // let user override automatic dimensions if (fixmaxx != 0) maxx = amaxx; else if (logx == 0) maxx += (maxx-minx) * .02; else maxx *= 1.1; if (fixminx != 0) minx = min(aminx, maxx); else if (logx == 0) minx -= (maxx-minx) * .02; else minx /= 1.1; if (fixmaxy != 0) maxy = amaxy; else if (logy == 0) maxy += (maxy-miny) * .02; else maxy *= 1.1; if (fixminy != 0) miny = min(aminy, maxy); else if (logy == 0) miny -= (maxy-miny) * .02; else miny /= 1.1; int *imagedata[GRAPHPOINTS], id[GRAPHPOINTS][GRAPHHEIGHT]; if (1) for (int i = 0; i < GRAPHPOINTS; i++) imagedata[i] = id[i]; if (1) for (int i = 0; i < GRAPHPOINTS; i++) for (int j = 0; j < GRAPHHEIGHT; j++) imagedata[i][j] = bgcolor; // horizontal grid lines { if (logy != 0) { miny = log10(miny); if (!_finite(miny)) miny = 1e-10; maxy = log10(maxy); if (!_finite(maxy)) maxy = 1e10; } double ss = pow(10., ceil(log10(maxy-miny))-1); // pick a power of ten interval with 1-10 intervals over the data if ((maxy-miny)/ss < 3) ss *= .1; // assure at least 3 marks double firsttick = floor(miny/ss)-2; for (int ll = 0; ll < 40; ll++) { double yval = (firsttick+ll)*ss; if (!_finite(yval) || yval < miny || yval > maxy) continue; double vpos = (yval-miny)*(GRAPHHEIGHT-VMAR)/(maxy-miny) + VMAR; LineWrite(imagedata, GRAPHPOINTS, GRAPHHEIGHT, HMAR, vpos, GRAPHPOINTS, vpos, 0xc0c0c0, 1); TextWrite(imagedata, GRAPHPOINTS, GRAPHHEIGHT, HMAR, vpos, logy != 0 ? SISuffix(pow(10., yval), 3, 0) : SISuffix(yval, 3, 0), 0x000000, 1, .5); } } // vertical grid lines { if (logx != 0) { minx = log10(minx); if (!_finite(minx)) minx = 1e-10; maxx = log10(maxx); if (!_finite(maxx)) maxx = 1e10; } double ss = pow(10., ceil(log10(maxx-minx))-1); // pick a power of ten interval with 1-10 intervals over the data if ((maxx-minx)/ss < 3) ss *= .1; // assure at least 3 marks double firsttick = floor(minx/ss)-2; for (int ll = 0; ll < 40; ll++) { double xval = (firsttick+ll)*ss; if (!_finite(xval) || xval < minx || xval > maxx) continue; double hpos = (xval-minx)*(GRAPHPOINTS-HMAR)/(maxx-minx) + HMAR; LineWrite(imagedata, GRAPHPOINTS, GRAPHHEIGHT, hpos, VMAR, hpos, GRAPHHEIGHT, 0xc0c0c0, 1); char buf[1050], *bp = buf; if (logx == 0 && fmtx == 0) bp = SISuffix(xval, 3, 0); else if (logx == 1 && fmtx == 0) bp = SISuffix(pow(10., xval), 3, 0); else if (logx == 0 && fmtx == 1) sprintf(buf, "%.0f", xval); else sprintf(buf, "%.0f", xval); TextWrite(imagedata, GRAPHPOINTS, GRAPHHEIGHT, hpos, VMAR, bp, 0x000000, .5, 1); } } if (1) for (int ii = 0; ii < n; ii++) dope[ii].WriteToBitmap(imagedata, logx, logy, minx, maxx, miny, maxy, GRAPHPOINTS, GRAPHHEIGHT, cross); // double tick = SIRound(maxy); // LineWrite(imagedata, GRAPHPOINTS, GRAPHHEIGHT, 0, tick*GRAPHHEIGHT/(maxy-miny), 10, tick*GRAPHHEIGHT/(maxy-miny), 0x404000); if (logy != 0) { miny = pow(10., miny); maxy = pow(10., maxy); } if (logx != 0) { minx = pow(10., minx); maxx = pow(10., maxx); } fprintf(output, "\n"); // top legend only if a second graph present #if TOPLEGEND != 0 // { if (n > 1) fprintf(output, "\n", Out1, color2, SISuffix(pow(10, minx)), Out2, Out1, color2, SISuffix(pow(10, maxx)), Out2); #endif // } // main row fprintf(output, "", Out1, color1, SISuffix(maxy), Out2); fprintf(output, ""); #if TOPLEGEND != 0 // { if (n > 1) fprintf(output, "", Out1, color2, SISuffix(maxy), Out2); #endif // } fprintf(output, "\n"); // lower side legend fprintf(output, "", Out1, color1, Out2); #if TOPLEGEND != 0 // { if (n > 1) fprintf(output, "", Out1, color2, Out2); #endif // } fprintf(output, "\n"); // bottom legend fprintf(output, "\n", Out1, color1, SISuffix(minx), Out2, Out1, color1, SISuffix(maxx), Out2); // legend #if LEGEND != 0 // { fprintf(output, "\n", Out2); #endif // } // caption fprintf(output, "
%sK=%s%s%sK=%s%s
%s%s%s"); fprintf(output, "
", bgcolor); #if USEBMP // { fprintf(output, "", ImageStoreAdd(GRAPHPOINTS, GRAPHHEIGHT, imagedata)); #endif // } #if USEGIF && USEBMP // { fprintf(output, "
"); #endif // } #if USEGIF // { int **ip = imagedata; fprintf(output, "", GifImageStoreAdd(GRAPHPOINTS, GRAPHHEIGHT, &ip)); //fprintf(output, "", GifImageStoreAdd(GRAPHPOINTS, GRAPHHEIGHT, &ip)); //fprintf(output, "", GifImageStoreAdd(GRAPHPOINTS, GRAPHHEIGHT, &ip)); #endif // } fprintf(output, "
"); fprintf(output, "
%s%s%s
%s0.0%s%s0.0%s
%sK=%s%s%sK=%s%s
%s", Out1); if (1) for (int ii = 0; ii < n; ii++) fprintf(output, "%s ", Color[ii], dope[ii].Name != NULL ? dope[ii].Name->Name : "Measurement"); fprintf(output, "%s
%s%s%s
\n", Out1, title, Out2); // print csf table for Excel fprintf(output, "
\n"); if (0) { int MaxNumPoints = 0; if (1) for (int i = 0; i < n; i++) if (MaxNumPoints < dope[i].NumPoints) MaxNumPoints = dope[i].NumPoints; if (1) for (int i = 0; i < MaxNumPoints; i++) { int newline = 1; for (int j = 0; j < n; j++) { if (dope[j].NumPoints > 0) { if (newline == 0) fprintf(output, ", "); else newline = 0; if (i < dope[j].NumPoints) fprintf(output, "%.4f, %.4f", dope[j].Data[i].X, log10(dope[j].Data[i].Y)); else fprintf(output, " , "); } } fprintf(output, "
\n"); } } fprintf(output, "
\n"); fprintf(output, "
\n"); } int HTMLGraph::backtranslate(FILE *output, int x, int y, int dist) { int logx = 0, logy = 1; double xx = logx == 0 ? (x-HMAR)*(maxx-minx)/(width-HMAR) + minx : pow(10., (x-HMAR)*(maxx-minx)/(width-HMAR) + minx); double yy = logy == 0 ? ((height-y)-VMAR)*(maxy-miny)/(height-VMAR) + miny : pow(10., ((height-y)-VMAR)*(maxy-miny)/(height-VMAR) + miny); int ty = height-y-1; int tx = x-1; #define LX(x) (logx != 0 ? log10(x) : (x)) #define LY(y) ((y)) for (int i = 0; i < NumPoints; i++) { double rx = logx == 0 ? Data[i].X : log10(Data[i].X); double ry = logy == 0 ? Data[i].Y : log10(Data[i].Y); double x1 = (rx-LX(minx))*(width-HMAR)/(LX(maxx)-LX(minx)) + HMAR; double y1 = (ry-LY(miny))*(height-VMAR)/(LY(maxy)-LY(miny)) + VMAR; if (x1-tx <= dist && tx-x1 <= dist && y1-ty <= dist && ty-y1 <= dist) { //fprintf(output, "meef %s %s
\n", SISuffix(X[i]), SISuffix(Y[i])); //payload->HTMLDescription(output, X[i]); return 1; } } return 0; } HTMLGraph PlotData[NUMPLOTS]; #define FOREACHWORD(s, p, e) for (char *(p) = NULL, *(e) = (s); advance((p), (e)); ) #define FOREACHNUMBER(s, p, e) for (char *(p) = NULL, *(e) = (s); advancen((p), (e)); ) void Plotfcn(void *base, double amp, double horiz, eDataValidity real) { ((HTMLGraph *)base)->AddPoint(amp, horiz, NULL, NULL, real); // Ephemeral or Real } #define DIAGHDRMODE 0 #if DIAGHDRMODE != 0 #include "header.cpp" #endif // image buffer capability //struct ImageStore Buffer[IMAGESTORELIMIT]; IStore ImageStore; // search image store for an image matching the url int IStore::ImageStoreSearch(char *n) { for (int i = 0, e = InterlockedExchangeAdd(&BuffersTop, 0); i < e; i++) { if (i >= IMAGESTORELIMIT) break; if (InterlockedExchangeAdd((long *)&Buffer[i].MIME, 0) != 0) if (strcmp(Buffer[i].Name, n) == 0) return i; } return -1; } // clear buffers // atomically destroy the MIME type pointer to indicate unavailable // then atomically set the BuffersTop pointer to permit reuse void IStore::ImageStoreClear() { for (int i = 0; i < IMAGESTORELIMIT; i++) { InterlockedExchange((long *)&Buffer[i].MIME, 0); Buffer[i].Name[0] = 0; Buffer[i].Len = 0; #define IMAGESTOREPOINTER 1 #if IMAGESTOREPOINTER != 0 delete Buffer[i].Dope; #endif } InterlockedExchange(&BuffersTop, 0); } // Allocate an archival disk file, returning an open FILE * for writing its contents // If link == 1, create a hyperlink to this file from archive.htm // If stash != NULL, store the (relative) file name FILE *IStore::ArchiveFile(const char *notation, const char *extension, int link, char *stash) { time_t long_time; time(&long_time); // additional segment char fraction[10]; fraction[0] = 0; for (int i = 0; i < 50; i++) { struct tm *newtime = localtime(&long_time); const char *mon[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", }; char fn[200], fn2[200]; sprintf(fn, "%s-%02d%s%02d-%02dh%02dm%02ds%s.%s", notation, newtime->tm_mday, mon[newtime->tm_mon], newtime->tm_year-100, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, fraction, extension); sprintf(fn2, "archive/%s", fn); if (stash != NULL) sprintf(stash, "%s", fn); // create the directory _mkdir("archive"); // see if the file exists FILE *rval = fopen(fn2, "r"); // doesn't exist, see if we can make it if (rval == NULL) { rval = fopen(fn2, "wb+"); //fclose(rval); //rval = fopen(fn2, "wb+"); } // oops, exists, close it and try another else { fclose(rval); rval = NULL; } // got one if (rval != NULL) { if (link != 0) { FILE *ff = fopen("archive.htm", "a"); fprintf(ff, "%s
\n", fn, fn); fclose(ff); } //printf("file %s\n", fn2); return rval; } sprintf(fraction, ".%02x", myrand()&0xff); } ASSERTALWAYS(0); return NULL; } void ServeData::Set(unsigned int s) { URI = NULL; index = NULL; p = NULL; lastwrite = 0; theClient = s; argc = 0; name = NULL; value = NULL; } void ServeData::FreeUp() { if (URI != NULL) free(URI); if (argc > 0) { while (argc > 0) { free(name[argc - 1]); free(value[argc-- - 1]); } free(name); free(value); } if (p != NULL) free(p); Set(0); } void ServeData::CloseAndFreeUp() { closesocket(theClient); FreeUp(); } void ServeData::Serve404() { send(theClient, "HTTP/1.0 404\r\n", 14, 0); send(theClient, "Content-type: ", 14, 0); send(theClient, "text/html", 9, 0); send(theClient, "\r\n", 2, 0); send(theClient, "\r\n", 2, 0); send(theClient, "404 not found\n", 14, 0); CloseAndFreeUp(); } void ServeData::Serve200() { send(theClient, "HTTP/1.0 200\r\n", 14, 0); send(theClient, "Content-type: ", 14, 0); send(theClient, "text/html", 9, 0); send(theClient, "\r\n", 2, 0); send(theClient, "\r\n", 2, 0); } void ServeData::TitleTextNoDiskBackup(char *title) { Serve200(); send(theClient, "", 19, 0); send(theClient, title, strlen(title), 0); send(theClient, "\n", 22, 0); } FILE *ServeData::TitleTextOpenBufferFile(const char *title, const char *notation, const char *extension, int link, char *stash, int reload) { Serve200(); index = ImageStore.ArchiveFile(notation, extension, link, stash); fprintf(index, ""); if (reload > 0) fprintf(index, "", reload); fprintf(index, "%s\n", title); return index; } void ServeData::IncrementalWrite() { fseek(index, lastwrite, SEEK_SET); char buf[SENDBUFSZ]; int i; do { i = fread(buf, 1, sizeof buf, index); if (i > 0) send(theClient, buf, i, 0); } while (i == sizeof buf); lastwrite = ftell(index); } void ServeData::CloseBufferFile() { fseek(index, lastwrite, SEEK_SET); char buf[SENDBUFSZ]; int i; do { i = fread(buf, 1, sizeof buf, index); if (i > 0) send(theClient, buf, i, 0); } while (i == sizeof buf); fclose(index); CloseAndFreeUp(); } void ServeData::BasicServe(const char *title, const char *msg) { FILE *index = TitleTextOpenBufferFile(title, "index", "htm", 0, NULL); fprintf(index, "%s\n", msg); fprintf(index, "\n"); CloseBufferFile(); } // URL encoding decoder // this will change %xx to the equivalent character // ** overwrites the input buffer ** char *ServeData::URLDecode(char *x) { char *out = x, *rval = x; int acc; int state = 0; for (int c; (c = *x++) != 0; ) { if (state == 0 && c == '+') *out++ = ' '; else if (state == 0 && c != '%') *out++ = c; else if (state == 0) { state = 1; acc = 0; } else { acc = (acc<<4) + ((c >= '0' && c <= '9') ? c - '0' : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : 0); if (state == 1) state = 2; else { *out++ = acc; state = 0; } } } *out = 0; return rval; } // convert a double, possibly with a SISuffix suffix void ServeData::SD(double &d, char *v) { sscanf(v, "%lf", &d); for (int i = strlen(v); --i >= 0; ) { if (v[i] == ' ') continue; else if (v[i] == 'y') d *= 1e-24; else if (v[i] == 'z') d *= 1e-21; else if (v[i] == 'a') d *= 1e-18; else if (v[i] == 'f') d *= 1e-15; else if (v[i] == 'p') d *= 1e-12; else if (v[i] == 'n') d *= 1e-9; else if (v[i] == 'u') d *= 1e-6; else if (v[i] == 'm') d *= 1e-3; else if (v[i] == 'k' || v[i] == 'K') d *= 1e3; else if (v[i] == 'M') d *= 1e6; else if (v[i] == 'g' || v[i] == 'G') d *= 1e9; else if (v[i] == 't' || v[i] == 'T') d *= 1e12; else if (v[i] == 'P') d *= 1e15; else if (v[i] == 'E') d *= 1e18; else if (v[i] == 'Z') d *= 1e21; else if (v[i] == 'Y') d *= 1e24; else continue; break; } } // convert an integer, possibly with a SI suffix void ServeData::SI(int &n, char *v) { double d; sscanf(v, "%lf", &d); for (int i = strlen(v); --i >= 0; ) { if (v[i] == ' ') continue; else if (v[i] == 'y') d *= 1e-24; else if (v[i] == 'z') d *= 1e-21; else if (v[i] == 'a') d *= 1e-18; else if (v[i] == 'f') d *= 1e-15; else if (v[i] == 'p') d *= 1e-12; else if (v[i] == 'n') d *= 1e-9; else if (v[i] == 'u') d *= 1e-6; else if (v[i] == 'm') d *= 1e-3; else if (v[i] == 'k' || v[i] == 'K') d *= 1e3; else if (v[i] == 'M') d *= 1e6; else if (v[i] == 'g' || v[i] == 'G') d *= 1e9; else if (v[i] == 't' || v[i] == 'T') d *= 1e12; else if (v[i] == 'P') d *= 1e15; else if (v[i] == 'E') d *= 1e18; else if (v[i] == 'Z') d *= 1e21; else if (v[i] == 'Y') d *= 1e24; else continue; break; } n = (int)d; } void ServeData::SS(char *&p, char *v) { if (p != NULL) free(p); p = strdup(URLDecode(v)); } void ServeData::SB(int &b, char *v) { b = stricmp(v, "on") == 0; } // local thread manager // NOTE: Does not include the main thread //#define MAXTHREADS 100 class cThreadsSubclass: public cThreads { int ActiveThreads; // number of threads being tracked, including still running and completed struct MyThread { #if __GNUC__ == 0 HANDLE hThread; // handle #else pthread_t hThread; #endif unsigned long ec; // exit code FILETIME t[4]; // create, end, kernel, user double dt[4]; // double precision version of time void Clear() { hThread = 0; ec = 0; for (int i = 0; i < 4; i++) t[i].dwLowDateTime = t[i].dwHighDateTime = 0, dt[i] = 0.; } // close operating system's thread handle and clear local data structure void Close() { WaitForSingleObject(hThread, 0); CloseHandle(hThread); Clear(); } // query operating system and load data to local storage void Load() { #if __GNUC__ == 0 GetExitCodeThread(hThread, &ec); GetThreadTimes(hThread, &t[0], &t[1], &t[2], &t[3]); for (int i = 0; i < 4; i++) { LARGE_INTEGER li; li.LowPart = t[i].dwLowDateTime; li.HighPart = t[i].dwHighDateTime; dt[i] = double(li.QuadPart)*100e-9; } #else #endif } // print a line fragment on the thread void Print(FILE *fd, int html) { fprintf(fd, "%s0x%08x%s", html?"":"", 123, html?"":""); char ecbuf[50]; if (ec == STILL_ACTIVE) sprintf(ecbuf, "STILL_ACTIVE"); else sprintf(ecbuf, "%08x", unsigned(ec)); SYSTEMTIME sc, se; FileTimeToSystemTime(&t[0], &sc); FileTimeToSystemTime(&t[1], &se); //char *ks = SISuffix(dt[2], 3, 1); //char *ds = SISuffix(dt[3], 3, 1); //fprintf(fd, "%s%02d:%02d:%02d%s%02d:%02d:%02d%s%ss%s%ss%s%s%s", html?"":" ", sc.wHour, sc.wMinute, sc.wSecond, html?"":" ", se.wHour, se.wMinute, se.wSecond, html?"":" ", SISuffix(dt[2], 3, 1), html?"":" ", SISuffix(dt[3], 3, 1), html?"":" ", ecbuf, html?"":""); } // Sort Threads-> Lowest ranked thread become candidate for replacement by a new thread. Rank is used for printing. int operator>(struct MyThread &x) { // still active tasks at top of list if ((ec == STILL_ACTIVE) != (x.ec == STILL_ACTIVE)) return ec == STILL_ACTIVE; // task with most runtime at top of list if (ec == STILL_ACTIVE) return dt[2]+dt[3] > x.dt[2]+x.dt[3]; // task ended longest ago at bottom of list of completed tasks else return dt[1] > x.dt[1]; } } Array[MAXTHREADS]; // internal function int LoadAndSort() { for (int i = 0; i < ActiveThreads; i++) Array[i].Load(); // shell sort int flag = 1, d = ActiveThreads; while (flag || (d>1)) { // boolean flag (true when not equal to 0) flag = 0; // reset flag to 0 to check for future swaps d = (d+1)/2; for (int i = 0; i < (ActiveThreads - d); i++) { if (Array[i + d] > Array[i]) { struct MyThread temp = Array[i + d]; // swap items at positions i+d and d Array[i + d] = Array[i]; Array[i] = temp; flag = 1; // indicate that a swap has occurred } } } return ActiveThreads; } public: // initialize data structure -- like a creator function void Initialize() { Threads = this; ActiveThreads = 0; for (int i = 0; i < ActiveThreads; i++) Array[i].Clear(); } // launch a thread, putting a reference to it in local storage void Add(void (__stdcall *f) (ServeData *), ServeData *p) { LoadAndSort(); // we are full; close and recycle last entry if (ActiveThreads == MAXTHREADS) Array[--ActiveThreads].Close(); #if __GNUC__ == 0 Array[ActiveThreads++].hThread = (HANDLE)_beginthreadex(NULL, 0, (unsigned int (__stdcall *)(void *))f, (void *)p, 0, NULL); #else pthread_create(&Array[ActiveThreads++].hThread, NULL, (void* (*)(void *))f, p); #endif } // print system status void Print(FILE *fd, int html) { fprintf(fd, "%sThread status %d tasks%sTask%shThread%sCreate%sEnd%sKernel%sUser%sExit Code%s", html?"\n\n":" "); for (int i = 0; i < ActiveThreads; i++) { fprintf(fd, "%s%d%s", html?"":" "); Array[i].Print(fd, html); fprintf(fd, "%s\n", html?"":""); } fprintf(fd, "%s", html?"
":"", LoadAndSort(), html?"
":":\n", html?"":" ", html?"":" ", html?"":" ", html?"":" ", html?"":" ", html?"":" ", html?"
":"", i, html?"
":""); } // close everything, waiting until active threads terminate void AllDone() { for (int i = 0; i < ActiveThreads; i++) Array[i].Close(); } }; cThreads *Threads; #if FANCYPAGE != 0 void FancyPageBegin(FILE *index, ServeData &qx) { fprintf(index, "Quantum Computer Simulator\n"); fprintf(index, "\n"); fprintf(index, "\n"); #if DIAGHDRMODE != 0 fprintf(index, "
 
%s
\n", HEADERMESSAGE); #endif fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); // fprintf(index, "1 nav"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); // fprintf(index, "2 nav"); fprintf(index, "%sIndex%s
", NOut1, NOut2); fprintf(index, "%sSuperstrider%s
", NOut1, NOut2); #if SAMPLECOMMANDS != 0 fprintf(index, "%sTest%s
", NOut1, NOut2); fprintf(index, "%sStatus%s
", NOut1, NOut2); fprintf(index, "%sY%s
", NOut1, NOut2); #endif fprintf(index, "%sHelp%s
", NOut1, NOut2); fprintf(index, "%sExit%s", NOut1, NOut2); fprintf(index, "
\n"); fprintf(index, "\n"); // fprintf(index, "3 nav"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\"Programs\"\n"); fprintf(index, "\"Sandia
\n"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); // fprintf(index, "body"); } void FancyPageEnd(FILE *index, ServeData &qx) { //fprintf(index, "body end"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "
\n"); fprintf(index, "Back to top of page || \n"); fprintf(index, "Questions and Comments || \n"); fprintf(index, "Acknowledgment and Disclaimer
\n"); fprintf(index, "
\n"); fprintf(index, "\n"); fprintf(index, "
\n"); fprintf(index, "\n"); #if DIAGHDRMODE != 0 fprintf(index, "
%s
 
\n", HEADERMESSAGE); #endif fprintf(index, "\n"); fprintf(index, "\n"); } #else int FancyPage(FILE *index, ServeData &qx, int WhatToDo) { fprintf(index, "fancy page\n"); return 0; } #endif // entity encode an asciz string, returning a malloc'd buffer char *EntityEncode(const char *x) { // protect from null input string if (x == NULL) x = ""; // a long string of """" grows 6x to """" char *rval = (char *)malloc(6 * strlen(x) + 1), *p = rval, c; for (; (c = *x) != 0; x++) if (c == '&') *p++ = '&', *p++ = 'a', *p++ = 'm', *p++ = 'p', *p++ = ';'; else if (c == '<') *p++ = '&', *p++ = 'l', *p++ = 't', *p++ = ';'; else if (c == '>') *p++ = '&', *p++ = 'g', *p++ = 't', *p++ = ';'; else if (c == '"') *p++ = '&', *p++ = 'q', *p++ = 'u', *p++ = 'o', *p++ = 't', *p++ = ';'; else *p++ = c; *p++ = 0; // set to correct length rval = (char *)realloc(rval, strlen(rval) + 1); return rval; } // these are the multi-threaded command handlers and have to be added manually void __stdcall IndexPageThread(ServeData *qx) { FILE *index = qx->TitleTextOpenBufferFile("Index Page", "index", "htm", 0, NULL); #if FANCYPAGE != 0 FancyPageBegin(index, *qx); #else fprintf(index, "Fancy Page Stub
\n"); #endif fprintf(index, "Index
"); fprintf(index, "Superstrider
"); #if SAMPLECOMMANDS != 0 fprintf(index, "Test
"); fprintf(index, "Status
"); fprintf(index, "Y
"); #endif fprintf(index, "Help
"); fprintf(index, "Exit"); #if FANCYPAGE != 0 FancyPageEnd(index, *qx); #else fprintf(index, "\n"); #endif qx->CloseBufferFile(); delete qx; } #if SAMPLECOMMANDS != 0 void __stdcall StatusPageThread(ServeData *qx) { // Part 1: define variables, default values, and HTML variable names // d for double, i for integer // variable name // default, do not surround with quotes // HTML variable names #define HTMLVARS \ I(ReloadTime, 3, f1) \ I(Factor2, 2, f2) \ D(Alpha, 1.23, a) \ D(LaserPowerdBm, -30, db) #define D(a, b, c) char *a = strdup(#b); double d##a; #define I(a, b, c) int a = b; HTMLVARS #undef D #undef I // Part 2: Parse input (no specific programmer involvement here) int cmd = -1; // process input, if any if (1) for (int i = 0; i < qx->argc; i++) { char *n = qx->name[i]; char *v = qx->value[i]; if (0) ; #define D(a, b, c) else if (strcmp(n, #c) == 0) qx->SS(a, v), qx->SD(d##a, v); #define I(a, b, c) else if (strcmp(n, #c) == 0) qx->SI(a, v); HTMLVARS #undef D #undef I else if (strcmp(n, "cmd") == 0) cmd = 0; } // print the header FILE *index = qx->TitleTextOpenBufferFile("Status Page", "test", "htm", 0, NULL, ReloadTime); #if FANCYPAGE != 0 FancyPageBegin(index, *qx); #else fprintf(index, "Fancy Page Stub
\n"); #endif // now execute Threads->Print(index, 1); // Part 3: Do entity encoding as needed (no specific programmer involvement here) #define D(a, b, c) char *encoded_##a = EntityEncode(a); #define I(a, b, c) HTMLVARS #undef D #undef I // Part 4: Output the HTML form // For reals, hard code the HTML variable name and append encoded_ in front of the corresponding program variable and use %s // For ints, hard code the HTML varibale name but just use the program variable and use %d fprintf(index, "

"); fprintf(index, "", ReloadTime); fprintf(index, "", Factor2); fprintf(index, "", encoded_Alpha); fprintf(index, ""); fprintf(index, "
Reload Time
Unused
Unused
"); // Part 5: Free temporaries #define D(a, b, c) free(a); free(encoded_##a); #define I(a, b, c) HTMLVARS #undef D #undef I #undef HTMLVARS #if FANCYPAGE != 0 FancyPageEnd(index, *qx); #else fprintf(index, "\n"); #endif qx->CloseBufferFile(); delete qx; } void __stdcall TestPageThread(ServeData *qx) { // defaults int Factor1 = 1; int Factor2 = 2; char *Alpha = strdup("1.23"); double dAlpha; // floats in both ascii and double precision int cmd = -1; // process input, if any if (1) for (int i = 0; i < qx->argc; i++) { char *n = qx->name[i]; char *v = qx->value[i]; if (strcmp(n, "f1") == 0) qx->SI(Factor1, v); else if (strcmp(n, "f2") == 0) qx->SI(Factor2, v); else if (strcmp(n, "a") == 0) qx->SS(Alpha, v), qx->SD(dAlpha, v); else if (strcmp(n, "cmd") == 0) qx->SI(cmd, v); } // print the header FILE *index = qx->TitleTextOpenBufferFile("Test Page", "test", "htm", 0, NULL); // now execute if (cmd == 0) { fprintf(index, "running the command"); time_t base = time(0L); if (1) for (time_t i = base; i < base + 10; i++) { while (time(0L) < i) ; fprintf(index, "%d
\n", i); qx->IncrementalWrite(); } } #if FANCYPAGE != 0 // input form at bottom of page. char *t0 = EntityEncode(Alpha); fprintf(index, "

"); fprintf(index, "
", Factor1); fprintf(index, "
", Factor2); fprintf(index, "
", t0); fprintf(index, ""); fprintf(index, "
"); free(t0); #endif fprintf(index, "\n"); qx->CloseBufferFile(); free(Alpha); delete qx; } #endif double PerformanceTime() { #if __GNUC__ == 0 LARGE_INTEGER f, t; QueryPerformanceFrequency(&f); QueryPerformanceCounter(&t); double tt = double(t.QuadPart)/double(f.QuadPart); return double(t.QuadPart)/double(f.QuadPart); #else //struct timespec now; //clock_gettime(CLOCK_MONOTONIC, &now); //return now.tv_sec + now.tv_nsec / 1000000000.0; #endif } void __stdcall YThread(ServeData *sd) { // print the header FILE *index = sd->TitleTextOpenBufferFile("Y Thread Background Activity", "tsssssest", "htm", 0, NULL); // NOTE: For some reason browsers don't render incrementally with FANCYPAGE // Maybe this is because the incremental output is in a table?? #if 0 //FANCYPAGE != 0 FancyPageBegin(index, *sd); #else fprintf(index, "Y Thread Background Activity
\n"); #endif sd->IncrementalWrite(); int base = (int)PerformanceTime(); int printcount = 0; if (1) for (int i = base; ; i++) { double togo = double(i+1) - PerformanceTime(); long mstogo = long(togo*1000.); if (mstogo > 0 && mstogo < 1000) Sleep(long(togo*1000.)); if (printcount++ < 20 || (printcount & 7) == 0) { fprintf(index, "%f (%d) ", PerformanceTime() - (double)base, int(mstogo)); sd->IncrementalWrite(); } double t = 0.0; for (int i = 0; i < 50000000; i++) t+=i; } #if 0 //FANCYPAGE != 0 FancyPageEnd(index, *sd); #else fprintf(index, "\n"); #endif sd->CloseBufferFile(); delete sd; } void GIFHeader(SOCKET theClient) { send(theClient, "HTTP/1.0 200\r\n", 14, 0); send(theClient, "Content-type: ", 14, 0); send(theClient, "image/gif", 9, 0); send(theClient, "\r\n", 2, 0); send(theClient, "\r\n", 2, 0); } void SuperSend(SOCKET theClient, const char *MatZ, int len1, const char *MatY, int len2, const char *fn) { if (len1 > 0) send(theClient, (char *)MatZ, len1, 0); if (len2 > 0) send(theClient, (char *)MatY, len2, 0); char fn2[200]; sprintf(fn2, "archive/%s", fn); // see if the file exists FILE *f = fopen(fn2, "r"); if (f != NULL) { fclose(f); return; } // doesn't exist, see if we can make it f = fopen(fn2, "wb+"); if (f == NULL) return; // write the data fwrite(MatZ, len1, 1, f); fwrite(MatY, len2, 1, f); fclose(f); } // helper to write a 1x1 pixel gif of a certain color void SmallGIFHelper(SOCKET theClient, unsigned char *tail, const char *fn) { GIFHeader(theClient); unsigned char header[73] = { 71, 73, 70, 56, 55, 97, 1, 0, 1, 0, 179, 0, 0, 0, 0, 0, 128, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 128, 128, 0, 128, 0, 128, 128, 192, 192, 192, 128, 128, 128, 255, 0, 0, 0, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 0, 255, 255, 255, 255, 255, 44, 0, 0, 0, 0, 1, 0, 1, 0, 0, 4, 2, }; SuperSend(theClient, (char *)header, 73, (char *)tail, 4, fn); //send(theClient, (char *)header, 73, 0); //send(theClient, (char *)tail, 4, 0); } // helper to write a 1x1 pixel gif of a certain color void BigGIFHelper(SOCKET theClient, unsigned char *MatZ, int len1, const char *fn) { GIFHeader(theClient); SuperSend(theClient, (char *)MatZ, len1, NULL, 0, fn); } static unsigned char quantumsimulator[2736] = { 71, 73, 70, 56, 55, 97, 18, 1, 62, 0, 247, 0, 0, 0, 0, 0, 128, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 128, 128, 0, 128, 0, 128, 128, 192, 192, 192, 192, 220, 192, 166, 202, 240, 0, 0, 0, 0, 0, 42, 0, 0, 85, 0, 0, 127, 0, 0, 170, 0, 0, 212, 0, 42, 0, 0, 42, 42, 0, 42, 85, 0, 42, 127, 0, 42, 170, 0, 42, 212, 0, 85, 0, 0, 85, 42, 0, 85, 85, 0, 85, 127, 0, 85, 170, 0, 85, 212, 0, 127, 0, 0, 127, 42, 0, 127, 85, 0, 127, 127, 0, 127, 170, 0, 127, 212, 0, 170, 0, 0, 170, 42, 0, 170, 85, 0, 170, 127, 0, 170, 170, 0, 170, 212, 0, 212, 0, 0, 212, 42, 0, 212, 85, 0, 212, 127, 0, 212, 170, 0, 212, 212, 42, 0, 0, 42, 0, 42, 42, 0, 85, 42, 0, 127, 42, 0, 170, 42, 0, 212, 42, 42, 0, 42, 42, 42, 42, 42, 85, 42, 42, 127, 42, 42, 170, 42, 42, 212, 42, 85, 0, 42, 85, 42, 42, 85, 85, 42, 85, 127, 42, 85, 170, 42, 85, 212, 42, 127, 0, 42, 127, 42, 42, 127, 85, 42, 127, 127, 42, 127, 170, 42, 127, 212, 42, 170, 0, 42, 170, 42, 42, 170, 85, 42, 170, 127, 42, 170, 170, 42, 170, 212, 42, 212, 0, 42, 212, 42, 42, 212, 85, 42, 212, 127, 42, 212, 170, 42, 212, 212, 85, 0, 0, 85, 0, 42, 85, 0, 85, 85, 0, 127, 85, 0, 170, 85, 0, 212, 85, 42, 0, 85, 42, 42, 85, 42, 85, 85, 42, 127, 85, 42, 170, 85, 42, 212, 85, 85, 0, 85, 85, 42, 85, 85, 85, 85, 85, 127, 85, 85, 170, 85, 85, 212, 85, 127, 0, 85, 127, 42, 85, 127, 85, 85, 127, 127, 85, 127, 170, 85, 127, 212, 85, 170, 0, 85, 170, 42, 85, 170, 85, 85, 170, 127, 85, 170, 170, 85, 170, 212, 85, 212, 0, 85, 212, 42, 85, 212, 85, 85, 212, 127, 85, 212, 170, 85, 212, 212, 127, 0, 0, 127, 0, 42, 127, 0, 85, 127, 0, 127, 127, 0, 170, 127, 0, 212, 127, 42, 0, 127, 42, 42, 127, 42, 85, 127, 42, 127, 127, 42, 170, 127, 42, 212, 127, 85, 0, 127, 85, 42, 127, 85, 85, 127, 85, 127, 127, 85, 170, 127, 85, 212, 127, 127, 0, 127, 127, 42, 127, 127, 85, 127, 127, 127, 127, 127, 170, 127, 127, 212, 127, 170, 0, 127, 170, 42, 127, 170, 85, 127, 170, 127, 127, 170, 170, 127, 170, 212, 127, 212, 0, 127, 212, 42, 127, 212, 85, 127, 212, 127, 127, 212, 170, 127, 212, 212, 170, 0, 0, 170, 0, 42, 170, 0, 85, 170, 0, 127, 170, 0, 170, 170, 0, 212, 170, 42, 0, 170, 42, 42, 170, 42, 85, 170, 42, 127, 170, 42, 170, 170, 42, 212, 170, 85, 0, 170, 85, 42, 170, 85, 85, 170, 85, 127, 170, 85, 170, 170, 85, 212, 170, 127, 0, 170, 127, 42, 170, 127, 85, 170, 127, 127, 170, 127, 170, 170, 127, 212, 170, 170, 0, 170, 170, 42, 170, 170, 85, 170, 170, 127, 170, 170, 170, 170, 170, 212, 170, 212, 0, 170, 212, 42, 170, 212, 85, 170, 212, 127, 170, 212, 170, 170, 212, 212, 212, 0, 0, 212, 0, 42, 212, 0, 85, 212, 0, 127, 212, 0, 170, 212, 0, 212, 212, 42, 0, 212, 42, 42, 212, 42, 85, 212, 42, 127, 212, 42, 170, 212, 42, 212, 212, 85, 0, 212, 85, 42, 212, 85, 85, 212, 85, 127, 212, 85, 170, 212, 85, 212, 212, 127, 0, 212, 127, 42, 212, 127, 85, 212, 127, 127, 212, 127, 170, 212, 127, 212, 212, 170, 0, 212, 170, 42, 212, 170, 85, 212, 170, 127, 212, 170, 170, 212, 170, 212, 212, 212, 0, 212, 212, 42, 212, 212, 85, 212, 212, 127, 212, 212, 170, 212, 212, 212, 0, 0, 0, 12, 12, 12, 25, 25, 25, 38, 38, 38, 51, 51, 51, 63, 63, 63, 76, 76, 76, 89, 89, 89, 102, 102, 102, 114, 114, 114, 127, 127, 127, 140, 140, 140, 153, 153, 153, 165, 165, 165, 178, 178, 178, 191, 191, 191, 204, 204, 204, 216, 216, 216, 229, 229, 229, 242, 242, 242, 255, 251, 240, 160, 160, 164, 128, 128, 128, 255, 0, 0, 0, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 0, 255, 255, 255, 255, 255, 44, 0, 0, 0, 0, 18, 1, 62, 0, 0, 8, 254, 0, 255, 9, 28, 72, 176, 160, 193, 131, 8, 19, 42, 92, 200, 176, 161, 195, 135, 16, 35, 74, 156, 72, 177, 162, 197, 139, 24, 51, 106, 220, 200, 177, 163, 199, 143, 32, 67, 138, 28, 73, 178, 164, 201, 147, 40, 83, 170, 92, 201, 178, 165, 203, 151, 48, 73, 214, 147, 32, 97, 2, 61, 133, 225, 104, 74, 136, 87, 47, 166, 207, 159, 5, 235, 245, 208, 89, 115, 94, 79, 160, 65, 135, 234, 156, 96, 212, 226, 45, 157, 140, 110, 34, 204, 73, 211, 157, 188, 163, 72, 179, 178, 124, 74, 84, 103, 60, 169, 89, 185, 118, 221, 9, 86, 34, 35, 157, 103, 224, 149, 37, 72, 85, 194, 34, 91, 243, 180, 202, 77, 217, 118, 108, 187, 175, 89, 235, 118, 189, 123, 243, 172, 132, 48, 77, 25, 182, 109, 247, 46, 238, 193, 182, 139, 10, 207, 93, 92, 50, 140, 206, 69, 238, 220, 189, 115, 76, 56, 92, 86, 199, 52, 33, 75, 166, 252, 206, 178, 223, 30, 182, 174, 58, 156, 7, 239, 157, 218, 169, 143, 21, 51, 94, 253, 81, 40, 205, 30, 145, 15, 204, 155, 23, 238, 64, 60, 195, 63, 93, 75, 128, 237, 78, 54, 109, 219, 113, 63, 247, 198, 186, 176, 222, 108, 122, 196, 9, 202, 75, 141, 155, 181, 243, 140, 186, 37, 180, 179, 37, 181, 158, 245, 122, 92, 39, 132, 59, 218, 150, 231, 63, 170, 140, 234, 254, 45, 215, 121, 203, 122, 65, 191, 52, 195, 32, 31, 8, 190, 30, 102, 73, 244, 148, 74, 167, 46, 240, 58, 122, 162, 55, 144, 143, 15, 255, 158, 222, 248, 9, 162, 213, 71, 148, 36, 7, 48, 55, 208, 125, 234, 97, 213, 94, 127, 201, 61, 199, 24, 102, 85, 173, 245, 143, 88, 195, 125, 167, 19, 95, 92, 133, 33, 159, 78, 97, 108, 39, 144, 94, 58, 185, 211, 20, 85, 97, 220, 240, 24, 60, 16, 74, 224, 206, 90, 41, 18, 21, 218, 120, 37, 158, 8, 207, 133, 7, 244, 36, 214, 88, 110, 41, 6, 98, 85, 35, 166, 103, 98, 102, 240, 120, 232, 32, 107, 32, 150, 71, 144, 88, 211, 245, 132, 88, 97, 55, 226, 216, 206, 85, 51, 225, 88, 213, 85, 59, 158, 225, 206, 61, 99, 25, 41, 208, 125, 68, 185, 3, 79, 129, 99, 89, 137, 101, 102, 212, 209, 35, 37, 115, 102, 158, 105, 85, 61, 85, 174, 57, 164, 115, 77, 210, 20, 32, 146, 182, 40, 201, 220, 141, 86, 78, 198, 33, 117, 232, 89, 9, 207, 152, 18, 156, 65, 221, 120, 52, 89, 41, 153, 45, 225, 216, 130, 99, 128, 245, 156, 241, 90, 100, 239, 188, 72, 148, 161, 145, 206, 152, 217, 59, 244, 160, 23, 134, 100, 248, 16, 149, 216, 60, 125, 122, 9, 168, 160, 254, 77, 10, 41, 162, 13, 190, 41, 215, 60, 56, 158, 70, 167, 157, 254, 151, 206, 35, 22, 100, 161, 197, 247, 232, 1, 74, 109, 10, 87, 61, 194, 29, 64, 232, 166, 239, 200, 182, 30, 171, 99, 157, 246, 143, 112, 240, 24, 37, 30, 135, 146, 9, 11, 102, 142, 244, 64, 72, 216, 1, 244, 196, 147, 90, 56, 185, 186, 179, 107, 175, 191, 54, 59, 207, 122, 170, 58, 87, 237, 143, 175, 125, 245, 170, 133, 177, 138, 133, 143, 155, 16, 122, 137, 150, 151, 70, 41, 186, 155, 59, 241, 60, 187, 110, 141, 5, 141, 75, 84, 15, 120, 245, 202, 157, 78, 247, 30, 69, 232, 167, 217, 158, 54, 240, 59, 132, 250, 25, 239, 163, 245, 2, 92, 97, 184, 67, 26, 7, 168, 116, 7, 200, 59, 31, 172, 57, 202, 10, 176, 106, 237, 190, 115, 102, 136, 95, 110, 220, 220, 64, 18, 19, 213, 78, 141, 254, 126, 40, 50, 123, 215, 190, 235, 221, 146, 132, 170, 25, 50, 77, 248, 168, 6, 241, 155, 188, 94, 104, 11, 160, 211, 221, 180, 164, 198, 52, 99, 42, 80, 199, 31, 239, 118, 79, 60, 132, 214, 44, 33, 201, 232, 245, 156, 50, 186, 18, 40, 205, 114, 172, 217, 226, 11, 115, 209, 61, 28, 157, 180, 208, 55, 171, 138, 94, 205, 146, 164, 230, 243, 157, 6, 70, 57, 47, 60, 217, 218, 226, 171, 60, 108, 179, 61, 207, 214, 75, 31, 40, 178, 112, 222, 65, 45, 181, 202, 84, 223, 106, 227, 254, 181, 105, 175, 221, 182, 60, 111, 111, 28, 119, 215, 185, 253, 165, 160, 78, 176, 189, 35, 86, 15, 76, 122, 218, 56, 90, 219, 65, 104, 101, 60, 16, 46, 242, 149, 117, 103, 137, 6, 183, 128, 97, 28, 254, 104, 97, 77, 215, 221, 214, 221, 80, 39, 150, 41, 90, 240, 228, 204, 92, 229, 151, 231, 172, 185, 224, 132, 47, 182, 227, 99, 218, 206, 179, 225, 88, 159, 198, 185, 151, 85, 49, 143, 245, 122, 208, 82, 205, 158, 153, 182, 244, 52, 121, 131, 117, 155, 227, 13, 109, 239, 184, 23, 198, 60, 81, 191, 71, 205, 117, 236, 90, 153, 61, 214, 58, 145, 241, 20, 103, 15, 74, 229, 254, 49, 173, 113, 233, 78, 211, 61, 242, 148, 10, 188, 128, 82, 98, 79, 175, 117, 93, 1, 24, 78, 242, 165, 11, 205, 229, 110, 221, 43, 38, 190, 4, 228, 155, 47, 253, 224, 212, 195, 20, 93, 122, 145, 129, 151, 64, 98, 6, 153, 250, 1, 45, 106, 235, 232, 82, 179, 142, 242, 191, 221, 188, 35, 82, 239, 187, 208, 244, 26, 184, 169, 200, 36, 75, 32, 105, 74, 207, 59, 26, 70, 19, 194, 128, 101, 48, 92, 123, 86, 212, 220, 97, 192, 250, 220, 142, 113, 16, 36, 148, 7, 251, 55, 23, 54, 149, 38, 128, 145, 186, 13, 86, 170, 245, 14, 72, 197, 35, 28, 241, 176, 69, 178, 212, 69, 175, 23, 70, 10, 95, 254, 36, 147, 135, 45, 106, 8, 169, 13, 222, 196, 56, 165, 49, 86, 125, 194, 241, 194, 83, 201, 144, 100, 21, 131, 84, 141, 144, 104, 154, 181, 144, 166, 138, 3, 161, 161, 100, 54, 40, 143, 28, 94, 176, 62, 66, 36, 226, 22, 241, 66, 69, 37, 178, 48, 43, 214, 121, 31, 219, 194, 17, 24, 130, 24, 199, 109, 215, 153, 13, 118, 68, 70, 143, 247, 177, 177, 65, 245, 168, 99, 219, 238, 72, 178, 227, 36, 39, 141, 123, 108, 99, 31, 215, 88, 29, 63, 6, 197, 144, 131, 4, 92, 28, 5, 153, 71, 53, 202, 131, 143, 245, 65, 228, 25, 91, 120, 29, 133, 152, 199, 32, 234, 82, 76, 37, 45, 185, 73, 136, 92, 39, 85, 36, 187, 164, 69, 68, 89, 156, 78, 78, 242, 148, 9, 201, 36, 255, 80, 201, 202, 86, 58, 4, 132, 171, 116, 165, 44, 103, 105, 144, 43, 154, 145, 150, 184, 204, 165, 27, 233, 241, 45, 80, 234, 242, 151, 192, 12, 166, 48, 135, 73, 204, 98, 26, 243, 152, 200, 76, 166, 50, 151, 201, 204, 102, 58, 243, 153, 208, 140, 166, 52, 167, 73, 205, 106, 98, 36, 74, 54, 65, 9, 85, 180, 227, 75, 107, 254, 242, 127, 76, 57, 138, 88, 162, 114, 146, 182, 184, 201, 155, 196, 20, 95, 191, 80, 23, 75, 141, 32, 134, 62, 232, 20, 166, 240, 248, 162, 66, 155, 141, 100, 73, 237, 254, 220, 82, 122, 4, 25, 207, 112, 85, 14, 82, 156, 241, 144, 45, 243, 137, 17, 124, 62, 228, 51, 161, 233, 102, 63, 25, 163, 27, 222, 248, 166, 54, 183, 137, 100, 47, 77, 98, 80, 135, 60, 109, 161, 56, 147, 79, 207, 234, 115, 157, 255, 136, 166, 61, 55, 226, 201, 178, 188, 130, 149, 236, 8, 169, 59, 24, 51, 157, 62, 241, 3, 174, 249, 73, 32, 63, 37, 237, 10, 26, 68, 185, 32, 154, 192, 71, 161, 24, 237, 72, 138, 86, 100, 144, 193, 212, 8, 70, 228, 2, 88, 139, 162, 214, 20, 10, 89, 237, 66, 95, 57, 152, 254, 198, 114, 15, 163, 12, 149, 38, 9, 181, 94, 87, 238, 177, 30, 18, 145, 107, 17, 65, 194, 105, 78, 221, 153, 37, 226, 188, 115, 169, 69, 115, 81, 248, 116, 150, 82, 231, 137, 237, 126, 18, 128, 139, 75, 85, 164, 150, 219, 77, 117, 59, 109, 10, 208, 86, 73, 162, 187, 0, 225, 51, 102, 134, 10, 42, 176, 228, 179, 136, 26, 157, 235, 103, 74, 93, 78, 24, 108, 97, 139, 122, 57, 170, 131, 83, 60, 44, 111, 34, 37, 15, 77, 73, 6, 109, 28, 82, 11, 94, 79, 37, 164, 185, 146, 132, 88, 93, 57, 205, 93, 153, 21, 26, 64, 233, 170, 139, 39, 154, 99, 7, 235, 20, 191, 192, 93, 170, 58, 119, 28, 169, 116, 82, 119, 172, 71, 37, 203, 58, 74, 73, 254, 28, 181, 108, 53, 47, 182, 49, 43, 88, 19, 181, 172, 73, 244, 133, 184, 164, 138, 45, 105, 107, 26, 216, 154, 50, 248, 22, 209, 94, 172, 180, 74, 29, 160, 148, 138, 219, 218, 121, 225, 203, 108, 126, 146, 10, 122, 232, 5, 92, 32, 234, 22, 37, 37, 163, 81, 96, 87, 246, 179, 127, 152, 173, 184, 127, 101, 142, 82, 51, 136, 35, 230, 166, 12, 186, 235, 91, 41, 91, 237, 101, 207, 235, 98, 183, 105, 133, 253, 45, 236, 12, 250, 221, 58, 209, 105, 108, 177, 82, 42, 132, 38, 240, 192, 118, 60, 134, 180, 231, 101, 22, 16, 225, 203, 94, 130, 186, 183, 35, 95, 51, 141, 124, 207, 71, 223, 255, 26, 87, 165, 128, 109, 217, 240, 180, 229, 14, 7, 55, 23, 54, 222, 105, 104, 133, 52, 60, 179, 253, 29, 120, 36, 51, 233, 220, 212, 230, 165, 184, 5, 123, 184, 193, 100, 98, 19, 226, 30, 151, 95, 9, 255, 133, 186, 158, 2, 48, 82, 143, 162, 41, 239, 72, 142, 94, 5, 254, 176, 72, 132, 231, 22, 109, 89, 235, 180, 155, 67, 177, 91, 234, 212, 192, 174, 124, 234, 96, 182, 251, 30, 105, 141, 135, 188, 143, 241, 198, 182, 231, 211, 49, 72, 164, 74, 20, 245, 33, 205, 196, 82, 19, 50, 115, 183, 103, 192, 237, 158, 137, 185, 82, 117, 159, 113, 219, 23, 153, 65, 193, 78, 202, 83, 190, 93, 156, 5, 225, 85, 79, 253, 173, 80, 203, 164, 253, 7, 1, 73, 216, 226, 14, 10, 141, 188, 18, 120, 71, 247, 226, 76, 222, 48, 108, 176, 39, 13, 92, 151, 182, 224, 42, 65, 3, 163, 57, 34, 46, 20, 99, 12, 3, 51, 80, 129, 52, 218, 209, 73, 4, 139, 45, 103, 24, 15, 34, 110, 16, 135, 58, 52, 204, 163, 233, 17, 197, 67, 29, 32, 137, 88, 169, 71, 167, 131, 197, 192, 48, 22, 241, 137, 144, 198, 226, 161, 167, 204, 166, 64, 18, 199, 56, 185, 133, 53, 184, 188, 43, 73, 89, 191, 250, 109, 138, 180, 142, 28, 37, 58, 235, 55, 62, 18, 57, 188, 156, 53, 173, 9, 185, 75, 53, 166, 214, 141, 146, 92, 53, 171, 73, 41, 19, 173, 26, 196, 148, 8, 129, 118, 40, 157, 173, 236, 106, 91, 251, 218, 216, 110, 72, 64, 0, 0, 59, }; static unsigned char logo[199] = { 71, 73, 70, 56, 57, 97, 151, 0, 60, 0, 179, 0, 0, 192, 192, 192, 204, 255, 255, 204, 204, 255, 204, 204, 204, 153, 204, 255, 153, 204, 204, 153, 153, 153, 102, 204, 204, 102, 153, 204, 102, 102, 102, 51, 153, 204, 51, 51, 51, 0, 153, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 249, 4, 1, 0, 0, 0, 0, 44, 0, 0, 0, 0, 151, 0, 60, 0, 0, 4, 116, 16, 200, 73, 171, 189, 56, 235, 205, 187, 255, 96, 40, 142, 100, 105, 158, 104, 170, 174, 108, 235, 190, 112, 44, 207, 116, 109, 223, 120, 174, 239, 124, 239, 255, 192, 160, 112, 72, 44, 26, 143, 200, 164, 114, 201, 108, 58, 159, 208, 168, 116, 74, 173, 90, 175, 216, 172, 118, 203, 237, 122, 191, 224, 176, 120, 76, 46, 155, 207, 232, 180, 122, 205, 110, 187, 223, 240, 184, 124, 78, 175, 219, 239, 248, 188, 126, 207, 239, 251, 255, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 31, 17, 0, 0, 59, }; static unsigned char bluegif[4] = { 144, 69, 0, 59, }; static unsigned char clear[44] = { 71, 73, 70, 56, 57, 97, 1, 0, 1, 0, 128, 0, 0, 255, 255, 255, 0, 0, 0, 33, 249, 4, 1, 0, 0, 0, 0, 44, 0, 0, 0, 0, 1, 0, 1, 0, 64, 2, 2, 132, 81, 0, 59, 0, }; static unsigned char bkgrnd[83] = { 71, 73, 70, 56, 57, 97, 220, 5, 1, 0, 128, 255, 0, 255, 255, 255, 0, 51, 102, 44, 0, 0, 0, 0, 220, 5, 1, 0, 0, 2, 50, 140, 143, 169, 203, 237, 15, 163, 156, 148, 129, 139, 179, 222, 188, 251, 15, 134, 226, 72, 150, 230, 137, 166, 234, 202, 182, 238, 11, 199, 242, 76, 215, 246, 141, 231, 250, 206, 247, 254, 15, 12, 10, 135, 196, 162, 241, 136, 156, 21, 0, 0, 59, }; void GIFEncode(FILE *out, const char *code) { char fname[100]; sprintf(fname, "%s.gif", code); FILE *test = fopen(fname, "rb"); int len = 0; int c; while ((c = fgetc(test)) != -1) len++; fclose(test); test = fopen(fname, "rb"); fprintf(out, " else if (stricmp(File, \"%s\") == 0) {\n static unsigned char %s[%d] = { ", fname, code, len); len = 0; while ((c = fgetc(test)) != -1) { fprintf(out, "%d, ", c); if (++len % 256 == 0) fprintf(out, "\n "); } fprintf(out, "};\n BigGIFHelper(theClient, %s, %d);\n }\n", code, len); fclose(test); } int main(int argc, char* argv[]) { // helper code to generate USEGIF writing code // create a 1x1 pixel USEGIF in GIF87a uninterlaced format and convert to 77 integers with the code below if (0) { FILE *otest = fopen("images.cpp", "w"); GIFEncode(otest, "networkplanner"); fclose (otest); } printf("Superstrider beta 1.0. Usage: Access http://127.0.0.1 from a web browser.\n"); // initialize web serving #if __GNUC__ == 0 WSADATA wsdata; int rc = WSAStartup(MAKEWORD(1,1), &wsdata); if (rc) { printf("WSAStartup failed: error code = %d\n", rc); return 1; } int Local_Address_Family = AF_INET; int Socket_Type = SOCK_STREAM; int Protocol = IPPROTO_TCP; u_int s = socket(Local_Address_Family, Socket_Type, Protocol); if (s == (u_int)INVALID_SOCKET) { printf("Socket call failed\n"); return 1; } int yes = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int)); SOCKADDR_IN Address; Address.sin_family = Local_Address_Family; Address.sin_addr.s_addr = INADDR_ANY; Address.sin_port = htons(80); rc = bind(s, (const struct sockaddr *) &Address, sizeof(SOCKADDR_IN)); if (rc == SOCKET_ERROR) { printf("Error at bind()"); return 0; } rc = listen(s, 10); // 10 is the number of clients that can be queued if (rc == SOCKET_ERROR) { printf("Error at listen()"); return 0; } Threads = new cThreadsSubclass; Threads->Initialize(); // web serving loop for (int more = 1; more != 0; ) { //Threads->Print(); // each time through the loop, free all the contents of ss // if the request is satisfied in a thread, the thread is responsible for freeing class ServeData ss; ss.Set(accept(s, NULL, NULL)); if (ss.theClient == INVALID_SOCKET) { printf("Error at accept()"); return 0; } #else int pId, listenFd; socklen_t len; //store size of the address bool loop = false; struct sockaddr_in svrAdd, clntAdd; //create socket listenFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listenFd < 0) { printf("Cannot open socket\n"); return 0; } bzero((char*) &svrAdd, sizeof(svrAdd)); svrAdd.sin_family = AF_INET; svrAdd.sin_addr.s_addr = INADDR_ANY; svrAdd.sin_port = htons(80); //bind socket if (bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0) { printf("Cannot bind %d\n", errno); perror("bind"); return 0; } listen(listenFd, 5); Threads = new cThreadsSubclass; Threads->Initialize(); for (int more = 1; more != 0; ) { //printf("Listening\n"); // each time through the loop, free all the contents of ss // if the request is satisfied in a thread, the thread is responsible for freeing class ServeData ss; //this is where client connects. svr will hang in this mode until client conn len = sizeof(clntAdd); ss.Set(accept(listenFd, (struct sockaddr *)&clntAdd, &len)); if (ss.theClient < 0) { printf("Cannot accept connection\n"); return 0; } else { //printf("Connection successful\n"); } int rc; #endif int total = 0; char buf[10000]; do { rc = recv(ss.theClient, buf, sizeof buf, 0); if (rc < 0) break; ss.p = (char *)(total == 0 ? malloc(rc + 1) : realloc(ss.p, total + rc + 1)); memcpy(ss.p + total, buf, rc); total += rc; ss.p[total] = 0; } while (rc == sizeof buf); //printf("%s", ss.p); int methodget = ss.p != NULL && ss.p[0] == 'G' && ss.p[1] == 'E' && ss.p[2] == 'T' && ss.p[3] == ' '; int methodpost = ss.p != NULL && ss.p[0] == 'P' && ss.p[1] == 'O' && ss.p[2] == 'S' && ss.p[3] == 'T' && ss.p[4] == ' '; // got something badly formed, neither GET nor POST if (!methodget && !methodpost) { if (ss.p != NULL) free(ss.p); continue; } char *q = ss.p + (methodget ? 4 : 5), *e = q; while (*e != 0 && *e != ' ' && *e != '?') e++; ss.URI = (char *)malloc(e - q + 1); strncpy(ss.URI, q, e - q + 1); ss.URI[e - q] = 0; //printf("file %s\n", ss.URI); // POST: skip to after blank line if (methodpost != 0) while (e[0] != 0 && (e[-4] != '\r' || e[-3] != '\n' || e[-2] != '\r' || e[-1] != '\n')) e++; // GET: skip ? delimiter if (methodget != 0 && *e == '?') e++; while (1) { q = e; while (*e != 0 && *e != '&' && *e != '=' && *e != ' ' && *e != '\r' && *e != '\n') e++; if (e != q) { ss.name = (char **)(ss.argc++ == 0 ? malloc(sizeof(char *) * ss.argc) : realloc(ss.name, sizeof(char *) * ss.argc)); ss.name[ss.argc - 1] = (char *)malloc(e - q + 1); strncpy(ss.name[ss.argc - 1], q, e - q); ss.name[ss.argc - 1][e - q] = 0; //printf("%s", ss.name[ss.argc - 1]); if (*e == '=') { q = ++e; while (*e != 0 && *e != '&' && *e != ' ' && *e != '\r' && *e != '\n') e++; } else e = q; ss.value = (char **)(ss.argc == 1 ? malloc(sizeof(char *) * ss.argc) : realloc(ss.value, sizeof(char *) * ss.argc)); ss.value[ss.argc - 1] = (char *)malloc(e - q + 1); strncpy(ss.value[ss.argc - 1], q, e - q); ss.value[ss.argc - 1][e - q] = 0; //printf("=%s\n", ss.value[ss.argc - 1]); } if (*e != '?' && *e != '&') break; else e++; } //printf("foo\n"); char *Path = ss.URI; char *File = Path; if (1) for (char *x = Path; *x != 0; x++) if (*x == '/') File = x + 1; ServeData *qx = new ServeData(&ss); int index; // need it in an expression later void __stdcall MMAccThread(ServeData *qx); // main web server // if a thread IS NOT launched, call ss.CloseAndFreeUp() and delete qx // if a thred IS launched, the thread needs to call ss.CloseAndFreeUp and delete qx on a copy of ss if (strlen(Path) > 3 && (index = ImageStore.ImageStoreSearch(Path+1)) >= 0) { send(ss.theClient, "HTTP/1.0 200\r\n", 14, 0); send(ss.theClient, "Content-type: ", 14, 0); send(ss.theClient, ImageStore.Buffer[index].MIME, strlen(ImageStore.Buffer[index].MIME), 0); send(ss.theClient, "\r\n", 2, 0); send(ss.theClient, "\r\n", 2, 0); send(ss.theClient, ImageStore.Buffer[index].Dope, ImageStore.Buffer[index].Len, 0); ss.CloseAndFreeUp(); delete qx; } else if (stricmp(Path, "/quantumsimulator.gif") == 0) { BigGIFHelper(ss.theClient, quantumsimulator, sizeof quantumsimulator, "quantumsimulator.gif"); ss.CloseAndFreeUp(); delete qx; } else if (stricmp(Path, "/logo.gif") == 0) { BigGIFHelper(ss.theClient, logo, sizeof logo, "logo.gif"); ss.CloseAndFreeUp(); delete qx; } #if DIAGHDRMODE != 0 else if (stricmp(Path, "/diag.gif") == 0) { BigGIFHelper(ss.theClient, diag, sizeof diag, "diag.gif"); ss.CloseAndFreeUp(); delete qx; } #endif else if (stricmp(Path, "/blue.gif") == 0) { BigGIFHelper(ss.theClient, bluegif, sizeof bluegif, "blue.gif"); ss.CloseAndFreeUp(); delete qx; } else if (stricmp(Path, "/clear.gif") == 0) { BigGIFHelper(ss.theClient, clear, sizeof clear, "clear.gif"); ss.CloseAndFreeUp(); delete qx; } else if (stricmp(Path, "/bkgrnd.gif") == 0) { BigGIFHelper(ss.theClient, bkgrnd, sizeof bkgrnd, "bkgrnd.gif"); ss.CloseAndFreeUp(); delete qx; } #if 0 // non multithreaded else if (stricmp(Path, "/") == 0 || stricmp(Path, "/index.htm") == 0) { ss.BasicServe("Index", "Fancy Page Stub No Sample Commands
\n" "Index
" "Superstrider
" #if SAMPLECOMMANDS != 0 "Test
" "Status
" "Y
" #endif "Help
" "Exit"); delete qx; } #else else if (stricmp(Path, "/") == 0 || stricmp(Path, "/index.htm") == 0) Threads->Add(IndexPageThread, qx); #endif else if (stricmp(Path, "/Superstrider") == 0) #if __GNUC__ == 0 Threads->Add(MMAccThread, qx); #else MMAccThread(qx); #endif #if SAMPLECOMMANDS != 0 else if (stricmp(Path, "/test") == 0) Threads->Add(TestPageThread, qx); else if (stricmp(Path, "/status") == 0) Threads->Add(StatusPageThread, qx); else if (stricmp(Path, "/y") == 0) Threads->Add(YThread, qx); #endif else if (strnicmp(Path, "/help", 5) == 0) { ss.BasicServe("Help", "help page"); delete qx; } else if (strnicmp(Path, "/exit", 5) == 0) { ss.BasicServe("Exit", "Exit"); delete qx; more = 0; } else { ss.Serve404(); delete qx; } _CrtCheckMemory(); } #if __GNUC__ == 0 Threads->AllDone(); ImageStore.ImageStoreClear(); closesocket(s); WSACleanup(); _CrtDumpMemoryLeaks(); return 0; #else //printf("Bye Erik. Calling getchar:\n"); //getchar(); #endif } #define MINKEY 0x80000000 #define MAXKEY 0x7fffffff #define IRANGE 6400 #define JRANGE 6400 // key in form of (i, j), i modulo irange and j modulo jrange // lexicographic order is (0, 0), (0, 1), (0, _), (1, 0), (1, 1) class Key { int I; public: Key() { } void SetIndex1(int ii, int ir = 0, int jr = 0) { I = ii; if (ir || jr) ASSERT(I < IRANGE*JRANGE); } void SetIndex2(int ii, int jj) { I = ii*JRANGE + jj; ASSERT(I < IRANGE*JRANGE); } int ij() { return I; } int i() const { return I/JRANGE; } int j() const { return I%JRANGE; } void Transpose() { I = I%JRANGE*JRANGE + I/JRANGE; } friend const bool operator<(const Key &a, const Key &b); friend const bool operator>(const Key &a, const Key &b); const bool operator==(const Key b) { return I == b.I; } bool mink() { return I == MINKEY; } bool maxk() { return I == MAXKEY; } bool unik() { return I == -1; } bool zerk() { return I == 0; } bool setbeyond(Key k) { *this = k; if (I+1 < IRANGE*JRANGE) { I++; return 0; } return 1; } }; const bool operator<(const Key &a, const Key &b) { return a.I < b.I; }//a.i() != b.i() ? a.i() < b.i() : a.j() < b.j(); } const bool operator>(const Key &a, const Key &b) { return a.I > b.I; }//a.i() != b.i() ? a.i() > b.i() : a.j() > b.j(); } Key mink(Key a, Key b) { return a < b ? a : b; } Key maxk(Key a, Key b) { return a > b ? a : b; } Key MinKey() { Key k; k.SetIndex1(MINKEY); return k; } Key MaxKey() { Key k; k.SetIndex1(MAXKEY); return k; } Key UniKey() { Key k; k.SetIndex1(-1); return k; } Key ZerKey() { Key k; k.SetIndex1(0); return k; } class Record { public: Key k; // key, such as multiple indices7 int Value; int Sequence; void Flag(int i) { // special key values for the empty part of a register k.SetIndex1(i); Value = 0; Sequence = 0; } }; #if SNCODE /* input clk0 clk1 clkx clkN-1 applied | compute 0 | compute 1 | compute x | compute N-1| compute 0 | | | | | next LSB LSB+1 LSB input valid valid TIME --> */ class Bit { char Wire; // This is the main bit; the only one is there is only one char Data; // Alternate data bit (local only) char Prfx; // parallel prefix or suffix calculation (local only) char Flag; // delete flag (local only) public: operator char() { ASSERT(!(Wire&~1)); return Wire; } char D() { ASSERT(!(Data&~1)); return Data; } char P() { ASSERT(!(Prfx&~1)); return Prfx; } char F() { ASSERT(!(Flag&~1)); return Flag; } void SetAll(char f, char p, char d, char w) { ASSERT(!(f&~1) && !(p&~1) && !(d&~1) && !(w&~1)); Flag = f; Prfx = p; Data = d; Wire = w; } void SetAllZ(char b) { SetAll(0, 0, 0, b); } void SetBit(char v) { ASSERT((v&~1) == 0); Wire = v&1; } void operator=(Bit b) { SetAllZ(b); } // this is weird. Looks like a structure assignment, but only assigns one bit void operator=(char v) { SetBit(v); } }; class SerialOp { public: char Op; // the following variables are the program, set at the beginning and reused int Arg; int Tap; // port of the network, or address number Bit Out; // result of the operation on the just-completed clock cycle char FullAdd(char Cy, char A, char B, char &NewCy) { NewCy = (Cy&1)+(A&1)+(B&1) > 1; return Cy^A^B & 1; } char FullSub(char Cy, char A, char B, char &NewCy) { char Diff = FullAdd(!Cy, A, 1-B, NewCy); NewCy = !NewCy; return Diff; } // the following are data specific to each application of the network and are set to zero before each run virtual void reset() { } virtual void vop(int, Bit, Bit) { }; }; #if BIG==2 #define SNDEPTH 3 // depth of the sorting network, or log2 K + 1 (+1 becuase the networks sorts Acc and memory, each of size K) #define SNLOGPORTS 7 #define SNWLEN 4 // word length -- needs to be long enough to hold max key size. Coordinate K with the input data generator. #elif BIG==1 #define SNDEPTH 9 // depth of the sorting network, or log2 K + 1 (+1 becuase the networks sorts Acc and memory, each of size K) #define SNLOGPORTS 511 #define SNWLEN 12 // word length -- needs to be long enough to hold max key size. Coordinate K with the input data generator. #elif BIG==0 #define SNDEPTH 3 // depth of the sorting network, or log2 K + 1 (+1 becuase the networks sorts Acc and memory, each of size K) #define SNLOGPORTS 63 #define SNWLEN 7 // word length -- needs to be long enough to hold max key size. Coordinate K with the input data generator. #endif class BitonicSwap: public SerialOp { char Saw; // we Saw a difference char Swp; // when we Saw a difference, the difference indicated a swap public: void reset() { Saw = Swp = 0; } void vop(int bitnum, Bit, Bit); }; void BitonicSwap::vop(int bitnum, Bit Inp, Bit Tap) { char T_Rst = bitnum <= 0; // reset state now char C_Lk1 = Op == '^'; // bitonic merge looking for a 1 due to arrow direction (as opposed to a 0) if (T_Rst) Saw = Swp = 0; // reset if (Saw == 0) { // haven't seen a difference if (Inp == Tap) Out = Inp; // no difference, so it doesn't matter which we copy else if (Inp == C_Lk1) Out = Inp, Saw = 1; else Out = Tap, Saw = Swp = 1; } else if (Swp == 0) Out = Inp; else Out = Tap; } /* A record will go by key first, then the placeholder for the address, then the value If the keys are different, order the records per bitonic sort If the keys are the same, set a flag to this effect. Actually, the flag is the first bit of the address field. All other address bits are zero. Then, one of the matching entries gets the sum of the two values and the other gests all 1's */ class BitonicMergeAdd: public SerialOp { char Saw; // "saw" a key bit difference char Swp; // key bit difference indicated we should swap records char Cy; // carry bit for full adder public: void reset() { Saw = Swp = Cy = 0; } void vop(int bitnum, Bit, Bit); }; void BitonicMergeAdd::vop(int bitnum, Bit Inp, Bit Tap) { char T_Rst = bitnum <= 0; // time to reset the state char T_Key = bitnum < SNWLEN; // time when the key is going past char T_Tst = bitnum == SNWLEN; // time of the delete bit char T_Adr = bitnum < SNWLEN+SNDEPTH; // time when the address is going past char C_Lk1 = Op == '^'; // bitonic merge looking for a 1 due to arrow direction (as opposed to a 0) char See = !Saw && T_Key && (Inp ^ Tap); // Sees a difference in keys char O_Sum = FullAdd(Cy, Inp, Tap, Cy); // Add input data, where needed char NewSwp = Swp || See && (Inp ^ C_Lk1); // Updated state bit for whether the streams swap or not char O_Swp = NewSwp ? Tap : Inp; // Output in swap mode, as opposed to addition mode char O_ALU = !T_Adr&&O_Sum || !T_Adr&&C_Lk1 || C_Lk1&&T_Tst; // Output in addition mode char NewSaw = Saw || See; // Updated state bit for whether we say a difference in key or not Out = (Saw || T_Key) ? O_Swp : O_ALU; // Pick merge or arithmetic Saw = NewSaw; Swp = NewSwp; } /* Previous stages provide a sufficiently large address field, but where only the values 0 and 1 appear. 0 indicates a real record and 1 indicates a record to be deleted. Parallel operation is based on allreduce of the original 0 or 1 addresses, thus computing the total number of records to be deleted. However, the logic with each record does some local calculations, although the calculation differs depending on whether the record will be deleted It either sums the number of records to be deleted from lower or higher numbered records. On the last stage only, it computes the destination address for each records, performing a different calculation for real and deleted records. Deleted records are actually routed to the far end of the buffer in reverse order. This is necessary for the bitonic sorter to work properly in reverse as a distribution network All of the above require saving the original 0 or 1 address as a deletion flag The first stage has unique wiring to capture the deletion flag All stages have two full adders, one for allreduce and a second that computes the sum of the high/low address. This second adder changes its wiring a little depending on the deletion flag The last stage only has an additional full adder whose connections change considerably depending on the deletion flag. */ class SumAddr: public SerialOp { char AllCy; char PXxCy; char AdrCy; char DFlag; // flag (not a carry) public: void reset() { AllCy = PXxCy = AdrCy = DFlag = 0; } void vop(int bitnum, Bit, Bit); }; void SumAddr::vop(int bitnum, Bit In, Bit Tp) { char T_LSB = bitnum == 0; // this clock cycle is transferring the first bit of the address, the LSB char T_Rst = bitnum <= 0; // reset state now char T_Off = bitnum < 0 || bitnum >= SNDEPTH; // the algorithm is turned off now char C_Lk1 = Op == '^'; // bitonic merge looking for a 1 due to arrow direction (as opposed to a 0) char C_1st = (Tap^Arg) == 1; // identifies first and last stages of the network char C_Lst = (Tap^Arg) == 1<<(SNDEPTH-1); char C_1x1 = C_1st && T_LSB; // first stage and first bit, the LSB char S_Adr = (Tap & 1<= 0 && bitnum < SNWLEN) ; else if (bitnum < SNWLEN+SNDEPTH) Out.SetAllZ(Inp); else if (bitnum < SNWLEN+SNDEPTH+SNWLEN) Out = ShiftReg & one<<(SNWLEN+SNDEPTH) ? 1 : 0; else Out = ShiftReg & one< ops; }; class SortingNetwork { public: vector > Inp; vector Program; vector > Out; vector Rval; FunctionTiming WholeProgram; void InitSortingNetwork(int, int, int, int, int, FILE *); void RunSortNetwork(vector &, vector &, int, int, ServeData *, FILE *); } SN; void SortingNetwork::InitSortingNetwork(int K, int WordLen, int alen, int klen, int vlen, FILE *index) { int Stages = 0; // input Var. First bit effectively appears at clock -1 so the first register gets the first bit at the end of clock 0 WholeProgram.Inputs.Var[0] = VarTiming('K', 0, klen); WholeProgram.Inputs.Var[1] = VarTiming('A', klen, alen); WholeProgram.Inputs.Var[2] = VarTiming('v', klen+alen, vlen); // construct a "program counter" that advances as we add "instructions" WholeProgram.Outputs = WholeProgram.Inputs; DataTiming *d = &WholeProgram.Outputs; int bitflip; for (bitflip = 1; bitflip < 2*K/2; bitflip <<= 1) ; for (; bitflip != 0; bitflip >>= 1) { Program.resize(++Stages); // add a bitonic sort and add RowOps *newrow = &Program[Stages-1]; newrow->OpTiming.Inputs = *d; newrow->Offset = WholeProgram.Latency(); d->Var[0].Begin++; d->Var[1].Begin++; d->Var[2].Begin++; newrow->OpTiming.Outputs = *d; newrow->ops.resize(2*K); for (int rec = 0; rec < 2*K; rec++) { newrow->ops[rec] = new BitonicMergeAdd; newrow->ops[rec]->Op = rec&bitflip ? '^' : 'v'; newrow->ops[rec]->Tap = rec; newrow->ops[rec]->Arg = rec^bitflip; } } { Program.resize(++Stages); // add a Var reorganization unit RowOps *newrow = &Program[Stages-1]; newrow->OpTiming.Inputs = *d; newrow->Offset = WholeProgram.Latency(); d->Var[1].Begin++; // A is now the first bit; time bits off of this d->Var[0].Begin = d->Var[1].Begin + d->Var[1].Length; d->Var[2].Begin = d->Var[0].Begin + d->Var[0].Length; newrow->OpTiming.Outputs = *d; newrow->ops.resize(2*K); for (int rec = 0; rec < 2*K; rec++) { newrow->ops[rec] = new DataReorg; newrow->ops[rec]->Op = 'd'; newrow->ops[rec]->Tap = rec; newrow->ops[rec]->Arg = 0; } } for (bitflip = 1; bitflip <= 2*K/2; bitflip <<= 1) { Program.resize(++Stages); // add address management RowOps *newrow = &Program[Stages-1]; newrow->OpTiming.Inputs = *d; newrow->Offset = WholeProgram.Latency(); d->Var[0].Begin++; d->Var[1].Begin++; d->Var[2].Begin++; newrow->OpTiming.Outputs = *d; newrow->ops.resize(2*K); for (int rec = 0; rec < 2*K; rec++) { newrow->ops[rec] = new SumAddr; newrow->ops[rec]->Op = rec&bitflip ? '^' : 'v'; newrow->ops[rec]->Tap = rec; newrow->ops[rec]->Arg = rec^bitflip; } } for (bitflip = 1; bitflip <= 2*K/2; bitflip <<= 1) { Program.resize(++Stages); // add a bitonic sort and add RowOps *newrow = &Program[Stages-1]; newrow->OpTiming.Inputs = *d; newrow->Offset = WholeProgram.Latency(); d->Var[0].Begin++; d->Var[1].Begin++; d->Var[2].Begin++; newrow->OpTiming.Outputs = *d; newrow->ops.resize(2*K); for (int rec = 0; rec < 2*K; rec++) { newrow->ops[rec] = new BitonicSwap; newrow->ops[rec]->Op = rec&bitflip ? '^' : 'v'; newrow->ops[rec]->Tap = rec; newrow->ops[rec]->Arg = rec^bitflip; } } { fprintf(index, "\n"); for (int stage = 0; stage < Stages; stage++) { px = Program[stage].OpTiming.Outputs.Var; fprintf(index, ""); } fprintf(index, "\n"); } for (int recnum = 0; recnum < 2*K; recnum++) { fprintf(index, "", recnum); for (int stage = 0; stage < Stages; stage++) fprintf(index, "", Program[stage].ops[recnum]->Op, Program[stage].ops[recnum]->Arg); fprintf(index, "\n"); } fprintf(index, "
"); VarTiming *px = WholeProgram.Inputs.Var; for (int i = 0; i < 3; i++) fprintf(index, "%c:%d-%d
", px[i].Name, px[i].Begin, px[i].Begin + px[i].Length - 1); px = WholeProgram.Outputs.Var; for (int i = 0; i < 3; i++) fprintf(index, "%c:%d-%d
", px[i].Name, px[i].Begin, px[i].Begin + px[i].Length - 1); fprintf(index, "
"); for (int i = 0; i < 3; i++) fprintf(index, "%c:%d-%d
", px[i].Name, px[i].Begin, px[i].Begin + px[i].Length - 1); fprintf(index, "
%d:%c%d
\n"); } void SortingNetwork::RunSortNetwork(vector &Acc, vector &Mem, int K, int WordLen, ServeData *qx, FILE *index) { #if BIG==2 int PrintIO = 1; int PrintFirst = 1; int PrintLast = 1; int PrintAll = 0; #elif BIG==1 int PrintIO = 1; int PrintFirst = 1; int PrintLast = 1; int PrintAll = 0; #elif BIG==0 int PrintIO = 1; int PrintFirst = 1; int PrintLast = 1; int PrintAll = 0; #endif // clear internal state for (unsigned st = 0; st < Program.size(); st++) for (unsigned i = 0; i < Program[st].ops.size(); i++) { Program[st].ops[i]->reset(); Program[st].ops[i]->Out.SetAllZ(0); } // set inputs Inp.clear(); Inp.resize(2*K); for (int i = 0; i < 2*K; i++) Inp[i].resize(WholeProgram.Inputs.Len()); // key msb first, value lsb first for (int i = 0; i < K; i++) { int k = i < int(Acc.size()) ? Acc[i].k.ij() : 0; int v = i < int(Acc.size()) ? int(Acc[i].Value) : 0; for (int bitnum = 0; bitnum < WordLen; bitnum++) Inp[i][WordLen-1-bitnum].SetAllZ(k&1<= 0; ) { int k = i < int(Mem.size()) ? Mem[i].k.ij() : 0; int v = i < int(Mem.size()) ? int(Mem[i].Value) : 0; for (int bitnum = 0; bitnum < WordLen; bitnum++) Inp[2*K-i-1][WordLen-1-bitnum].SetAllZ(k&1<= 0; ) Out[i][bit].SetAllZ(0); } // number of clocks will be the output stream length + latency unsigned clocks = WholeProgram.LastBit() - WholeProgram.FirstBit() - 1; for (unsigned pass = 0; pass < clocks; pass++) { Rval.clear(); // sweep backwards to avoid overwriting registers for (int st = int(Program.size()); --st >= 0; ) { // walk through all 2*K records for (int rec = 0; rec < 2*K; rec++) { // at the end of a sweep, reg represents the output of the calculation; input is from previous reg or the input // if st == 0, input is a bit from the input else input is reg[st-1] Bit z; z.SetAllZ(0); Bit &ia = st == 0 ? (pass < unsigned(WordLen*2+SNDEPTH) ? Inp[rec][pass] : z) : Program[st-1].ops[rec]->Out; int lnk = Program[st].ops[rec]->Arg; if (lnk < 0 || lnk >= 2*K) lnk = 0; Bit &ix = st == 0 ? (pass < unsigned(WordLen*2+SNDEPTH) ? Inp[lnk][pass] : z) : Program[st-1].ops[lnk]->Out; // state Program[st].ops[rec]->vop(pass-Program[st].Offset, ia, ix); // output is a bit in reg, but also copy to the output print area if (st == int(Program.size())-1) { int idx = pass-WholeProgram.Latency()+1; if (idx >= 0 && idx < int(Out[rec].size())) Out[rec][idx] = Program[st].ops[rec]->Out; } } } if (pass == 0 && PrintFirst == 0 && PrintAll == 0) continue; if (pass == clocks-1 && PrintLast == 0 && PrintAll == 0) continue; if (pass != 0 && pass != clocks-1 && PrintAll == 0) continue; // header line of network status fprintf(index, "", pass); VarTiming *px = WholeProgram.Inputs.Var; if (PrintIO) for (int bit = WholeProgram.Inputs.Len(); --bit >= 0; ) fprintf(index, "", bit >= px[0].Begin && bit < px[0].Begin + px[0].Length ? px[0].Name : bit >= px[1].Begin && bit < px[1].Begin + px[1].Length ? px[1].Name : bit >= px[2].Begin && bit < px[2].Begin + px[2].Length ? px[2].Name : '*'); for (int st = 0; st < int(Program.size()); st++) fprintf(index, ""); px = WholeProgram.Outputs.Var; int offset = min(px[0].Begin, min(px[1].Begin, px[2].Begin)); if (PrintIO) for (int bit = WholeProgram.Outputs.Len(); --bit >= 0; ) fprintf(index, "", bit+offset >= px[0].Begin && bit+offset < px[0].Begin + px[0].Length ? px[0].Name : bit+offset >= px[1].Begin && bit+offset < px[1].Begin + px[1].Length ? px[1].Name : bit+offset >= px[2].Begin && bit+offset < px[2].Begin + px[2].Length ? px[2].Name : '*'); fprintf(index, "\n"); // body of network status // TODO: remove hard-coded variables for (int rec = 0; rec < 2*K; rec++) { fprintf(index, ""); int k = 0, v = 0, del; for (int bitnum = 0; bitnum < WordLen; bitnum++) k = 2*k + Inp[rec][bitnum]; for (int bitnum = 0; bitnum < WordLen; bitnum++) v = 2*v + Inp[rec][WordLen*2-1-bitnum+SNDEPTH]; fprintf(index, "", k, v); if (PrintIO) for (int bit = WholeProgram.Inputs.Len(); --bit >= 0; ) fprintf(index, "%d", bit==pass ? " bgcolor=red" : "", Inp[rec][bit]); for (int st = 0; st < int(Program.size()); st++) fprintf(index, "", Program[st].ops[rec]->Out); if (PrintIO) for (int bit = WholeProgram.Outputs.Len(); --bit >= 0; ) fprintf(index, "%d", bit==pass-WholeProgram.Latency()+1 ? " bgcolor=red" : "", Out[rec][bit]); k = 0; v = 0; del = 0; for (int bitnum = 0; bitnum < WordLen; bitnum++) k = 2*k + Out[rec][bitnum+SNDEPTH]; for (int bitnum = 0; bitnum < WordLen; bitnum++) v = 2*v + Out[rec][2*WordLen+SNDEPTH-1-bitnum]; int delbefore = 0, a = 0, nodela = 0, delsv = 0, ua = 0; for (int bitnum = 0; bitnum < SNDEPTH; bitnum++) a = 2*a + Out[rec][SNDEPTH-1-bitnum].D(); for (int bitnum = 0; bitnum < SNDEPTH; bitnum++) delbefore = 2*delbefore + Out[rec][SNDEPTH-1-bitnum].P(); for (int bitnum = 0; bitnum < SNDEPTH; bitnum++) delsv = 2*delsv + Out[rec][SNDEPTH-1-bitnum].F(); for (int bitnum = 0; bitnum < SNDEPTH; bitnum++) ua = 2*ua + Out[rec][SNDEPTH-1-bitnum]; del = delsv; int indexnodel = nodela; if (pass == clocks-1) { Record rt; rt.k.SetIndex1(k, 65536, 1); rt.Value = v; Rval.push_back(rt); } fprintf(index, "", k, v); fprintf(index, "\n"); } fprintf(index, "
%d%c%c
[%d]=%d%d[%d]=%d
\n"); qx->IncrementalWrite(); } } #endif bool RecordSort1(Record i, Record j) { return i.k < j.k; } bool RecordSort2(Record i, Record j) { return j.k > i.k; } bool RecordSort3(Record i, Record j) { return (i.Sequence < j.Sequence); } #define OVLIST \ OV(Cl, 1, Reset memory) \ OV(Av, 2, Vector tree insertion) \ OV(Mx, 3, Maximum) \ OV(Rx, 103, Return from maximum) \ OV(Mn, 4, Minimum) \ OV(Rn, 104, Return from minimum) \ OV(Nm, 5, Normalize) \ OV(R2, 105, Normalize phase 2) \ OV(R3, 105, Normalize phase 3) \ OV(Aw, 6, Vector tree insertion) \ OV(Sp, 10, Span tree starting with A-side subtree) \ OV(Fi, 12, Find row with key) \ OV(Su, 13, Find row beyond key) \ OV(Mm, 14, Matrix multiply) #define N_ Opcodes(0) #define OV(s, n, t) s = n, enum Opcodes { OVLIST }; // no data #undef OV #define VARLIST \ VAR(NOP, -1, no operation) \ VAR(LPV, 0, up to K below-pivot records to low side) \ VAR(LPG, 1, below-pivot records beyond the goal to low side) \ VAR(LIX, 2, max and min part 2) \ VAR(LAA, 3, up to num inputs to low side) \ VAR(LSC, 4, smallest records to caller) \ VAR(HLD, 5, divider) \ VAR(HPV, 5, up to K above-pivot records to high side) \ VAR(HPG, 6, above-pivot records beyond the goal to high side) \ VAR(HIX, 7, max and min part 2) \ VAR(LBB, 8, up to num inputs to high side) \ VAR(HSC, 9, largest records to caller) \ VAR(NPV, 10, store to memory; assure pivot set) \ VAR(ZRM, 11, zero memory) \ VAR(DUP, 12, duplicate data to both memory and acc) \ VAR(TRN, 13, transpose duplicate data to both memory and acc) \ VAR(GEN, 14, new records in acc) \ VAR(ZRA, 15, put memory back and zero acc) #define VAR(s, n, t) s = n, enum Vars { VARLIST }; // no data #undef VAR enum AB { Z = 0, // default tree, row 0, code Z Y = 1, // second tree, row 1, code Y X = 2, // third tree, row 2, code X A = 3, // a subtree (left) B = 4, // b subtree (right) U = 5, // up (parent) N = 6, // linear next }; const char *OpTxt(Opcodes Opcode) { const char *Otxt; switch (Opcode) { case Mn: Otxt = "Minimum"; break; case Rn: Otxt = "Minimum2"; break; case Mx: Otxt = "Maximum"; break; case Rx: Otxt = "Maximum2"; break; case Nm: Otxt = "Normalize"; break; case R2: Otxt = "Normalize2"; break; case Cl: Otxt = "Clear"; break; case Av: Otxt = "Addvc"; break; default: Otxt = "XX"; break; } return Otxt; } class Superstrider; class Scalars { // class for integer arguments passed amongst rows Key Mn; // minimum key value in the subtree int SubSz_Goal; // the number of records in the subtree or the size goal for a subtree, depending on circumstance Key Mx; // maximum key value in the subtree int Fl; void Init(Key mn, int a, Key mx, int z) { Mn = mn; SubSz_Goal = a; Mx = mx; Fl = z; } public: Scalars(Key nn, int a, Key xx, int z) { Init(nn, a, xx, z); } Scalars(int a) { Init(MaxKey(), a, MinKey(), 0); } Scalars() { Init(MaxKey(), 0, MinKey(), 0); } Key Min() { return Mn; } int SzGl() { return SubSz_Goal; } Key Max() { return Mx; } int Flag() { return Fl; } }; class TreeRow { friend class DataPath; friend class MergeRow; Scalars ADat, BDat; // the goal of the particular function being executed at the moment int goal; // the goal of the particular function being executed at the moment public: int rowA; // RowA is left, lesser, or A branch -- or next item in freelist int rowB; // RowB is right, greater-equal, or B branch void Init() { ADat = BDat = Scalars(); goal = 0; rowA = 0; rowB = 0; } int NumA() { return ADat.SzGl(); } Key MinA() { return ADat.Min(); } Key MaxA() { return ADat.Max(); } void SetNumA(Scalars n) { ADat = n; } int NumB() { return BDat.SzGl(); } Key MinB() { return BDat.Min(); } Key MaxB() { return BDat.Max(); } void SetNumB(Scalars n) { BDat = n; } int Goal() { return goal; } void AllocAB(int &, Superstrider *, int); void FreeAB(int &, Superstrider *, int); int RowA() { return rowA; } int IsA() { return rowA != 0; } void SetRowA(int r) { rowA = r; } void AllocA(Superstrider *s, int K) { AllocAB(rowA, s, K); } void FreeA(Superstrider *s, int K) { FreeAB(rowA, s, K); ADat = Scalars(); } int RowB() { return rowB; } int IsB() { return rowB != 0; } void SetRowB(int r) { rowB = r; } void AllocB(Superstrider *s, int K) { AllocAB(rowB, s, K); } void FreeB(Superstrider *s, int K) { FreeAB(rowB, s, K); BDat = Scalars(); } }; class GenState { public: Key LowK, HighK; // lowest and highest keys of relevance -- it should be possible to compute these parameters on the fly Key ScanK; // Key while scanning int OFFSET; // matrix multiply generator offset int Block; // matrix multiply generator block void Init(Key l, Key h) { LowK.SetIndex2(l.i(), 0);// lowest key relevant to the generation will have the lowest i index and a 0 j index HighK.SetIndex2(h.i(), JRANGE-1);// highest key relevant to the generation will have the highest i index and the maximum j index ScanK = LowK; // pointer for find operations, initially undefined OFFSET = 0; // number of generated records to skip next time Block = 0; // the number of times this record has been processed already (only need to know 0 versus nonzero) } void Initxx(Key l, Key h) { LowK.SetIndex2(l.i(), 0);// lowest key relevant to the generation will have the lowest i index and a 0 j index HighK.SetIndex2(h.i(), JRANGE-1);// highest key relevant to the generation will have the highest i index and the maximum j index ScanK = LowK; // pointer for find operations, initially undefined OFFSET = 0; // number of generated records to skip next time Block = 0; // the number of times this record has been processed already (only need to know 0 versus nonzero) } void Init() { Initxx(UniKey(), UniKey()); } }; class Register { public: vector V; private: vector Out; public: int LX, RE, HX; // LX=low non-existent records, RE=real records, HX=high non-existent records public: unsigned Size() { return RE; } Key MinKey() { return RE > 0 ? V[LX].k : ::MaxKey(); } Key MaxKey() { return RE > 0 ? V[LX+RE-1].k : ::MinKey(); } void SetMeta(int L, int R, int H) { LX = L; RE = R; HX = H; } void Meta() { for (int i = 0; i < LX; i++) V[i].Flag(MINKEY); for (int i = 0; i < HX; i++) V[i+LX+RE].Flag(MAXKEY); } void Empty(int K) { SetMeta(0, 0, K); V.resize(K); for (int i = 0; i < HX; i++) V[LX+RE+i].Flag(MAXKEY); } Record &Access(int i) { return V[LX+i]; } vector &Raw() { return V; } Key FindPvt() { return V[LX+Size()/2].k; } int HowMany() { return RE; } // add one record, for input void AddSort(Record &r, int K) { #if 1 if (LX > 0) V[0] = r, LX--; else if (HX > 0) V[K-1] = r, HX--; else ASSERT(0); RE++; sort(V.begin(), V.end(), RecordSort1); #else RE++; LX--; for (int i = 0; i < K-1; i++) V[i] = V[i+1]; V[K-1] = r; sort(V.begin(), V.end(), RecordSort1); #endif } void ALU1y(int K, int OutUsed) { for (int i = 0; i < OutUsed; i++) V[i] = Out[i]; for (int i = OutUsed; i < K; i++) V[i].Flag(MAXKEY); SetMeta(0, OutUsed, K-OutUsed); sort(V.begin(), V.end(), RecordSort1); // compress int Wr = K-1; for (int Rd = K-1; --Rd >= 0; ) if (!V[Wr].k.mink() && !V[Wr].k.maxk() && V[Wr].k == V[Rd].k) { V[Wr].Value += V[Rd].Value; V[Wr].Sequence = min(V[Wr].Sequence, V[Rd].Sequence); RE--; LX++; } else V[--Wr] = V[Rd]; while (--Wr >= 0) V[Wr].Flag(MINKEY); double pi=3.12; } // Given two registers and an offset, generate up to K records of the matrix product // Currently, the K records are compressed after they are created, so there may be fewer than K in the returned data // returns the new value of the offset, or 0x7fffffff if the generation completes // Acc(k, i) * M(k, j) --> O(i, j) GenState ALU1x(Register &M, GenState skip, Key Mx2, int dbgrow, Opcodes dbgop, int dbgstep, int K, int printme, ServeData *qx, FILE *Index) { int OFFSET = skip.OFFSET; ASSERT(V.size() == K); ASSERT(M.V.size() == K); Out.resize(K); // process only real records int OutUsed = 0; sort(V.begin(), V.end(), RecordSort1); sort(M.V.begin(), M.V.end(), RecordSort1); printme = MMTRACE; if (printme) { #define OV(s, n, t) dbgop%100 == n ? #s : fprintf(Index, "%s>ALU1: %d.%s.%d%s[%d,%d]+%s [%d,%d]", NO1, dbgrow, OVLIST "?", dbgstep, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), skip.HighK.i(), skip.HighK.j()); #undef OV fprintf(Index, " {%d,%d}%s%s", Mx2.i(), Mx2.j(), NO2, NO1); fprintf(Index, " A:"); for (int i = LX; i < LX+RE; i++) fprintf(Index, "(%d,%d)", V[i].k.i(), V[i].k.j()); fprintf(Index, "%s%s", NO2, NO1); fprintf(Index, " M:"); for (int i = M.LX; i < M.LX+M.RE; i++) fprintf(Index, "(%d,%d)", M.V[i].k.i(), M.V[i].k.j()); fprintf(Index, "%s%s", NO2, NO1); } for (int Ai = LX, Ax = LX+RE, Mi = M.LX, Mx = M.LX+M.RE; Ai < Ax && Mi < Mx; ) // keys match in the i index, which is the most significant part in the sort sequence if (V[Ai].k.i() == M.V[Mi].k.i()) { // count the range of these indices int Al = 1, Ml = 1; int t1 = V[Ai].k.i(); int t2 = V[min(Ai+1,K-1)].k.i(); while (Ai+1 < Ax && V[Ai].k.i() == V[Ai+1].k.i()) Al++, Ai++; while (Mi+1 < Mx && M.V[Mi].k.i() == M.V[Mi+1].k.i()) Ml++, Mi++; if (0 && OFFSET >= Al*Ml) OFFSET -= Al*Ml; else { if (printme) fprintf(Index, " %dx%d", Al, Ml); {for (int i = 0; i < Al; i++) for (int j = 0; j < Ml; j++) // if there are more products than this call will satisfy, return to accumulate what we have so far and get the rest later if (OutUsed == K) { ALU1y(K, OutUsed); skip.OFFSET += OutUsed; if (printme) fprintf(Index, "%s%s[%d,%d]+%s%s\n", NO2, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), NO2); return skip; } // add a product to the list else { Key &KeyZ = V[Ai-Al+1+i].k; Key &k2 = M.V[Mi-Ml+1+j].k; Record r; r.k.SetIndex2(KeyZ.j(), k2.j()); int ii = KeyZ.j(); int jj = k2.j(); int a = V[Ai-Al+1+i].Value; int b = M.V[Mi-Ml+1+j].Value; r.Value = V[Ai-Al+1+i].Value * M.V[Mi-Ml+1+j].Value; r.Sequence = min(V[Ai-Al+1+i].Sequence, M.V[Mi-Ml+1+j].Sequence); if (OFFSET > 0) OFFSET--; else { Out[OutUsed++] = r; if (printme) fprintf(Index, " [%d,%d]=%d", KeyZ.j(), k2.j(), r.Value); } } } } Ai++, Mi++; } // keys don't match, so advance the smaller one else if (V[Ai].k.i() < M.V[Mi].k.i()) Ai++; else Mi++; //ALU1y(K, OutUsed); // if the last record to participate in this generation is in the row just fetched, terminate the generation // otherwise adjust the argument to find to get the next record by incrementing the key in lexicographic order, unless... // the increment would overflow the Key's field int i1 = LX+RE; Record r1 = i1 > 0 ? V[LX+RE-1]: Record(); int im = M.LX+M.RE; Record rm = M.V[M.LX+M.RE-1]; if (dbgstep != 3 && dbgstep != 4) { if (printme) fprintf(Index, "XX %s%s[%d,%d]+%s%s\n", NO2, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), NO2); ALU1y(K, OutUsed); return skip; } // the end key got deleted, so we need to examine the next block if (Mx2.zerk()) { if (skip.ScanK.setbeyond(V[LX+RE-1].k)) { //if (skip.ScanK.setbeyond(M.V[M.LX+M.RE-1].k)) { skip.OFFSET = 0x7fffffff; if (printme) fprintf(Index, "%s%s[%d,%d]+%s%s\n", NO2, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), NO2); ALU1y(K, OutUsed); return skip; } skip.Block++; if (skip.OFFSET == 78) double pi=3.14; skip.OFFSET = 0; if (printme) fprintf(Index, "%s%s[%d,%d]+%s%s\n", NO2, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), NO2); ALU1y(K, OutUsed); return skip; } skip.OFFSET = 0x7fffffff; if (printme) fprintf(Index, "%s%s[%d,%d]+%s%s\n", NO2, NO1, skip.ScanK.i(), skip.ScanK.j(), skip.OFFSET==0x7fffffff?"inf":SISuffix(skip.OFFSET), NO2); ALU1y(K, OutUsed); return skip; /*if (!Mx2.zerk() || skip.ScanK.setbeyond(M.V[M.LX+M.RE-1].k)) skip.OFFSET = 0x7fffffff; else { skip.Block++; skip.OFFSET = 0; } return skip;*/ } // append Acc with memory, sort, eliminate duplicates, and return LT and GE // changes Acc width from K to 2K void ALU1(Register &M, unsigned <, unsigned &GE, Key p, int K, Opcodes Op) { // merge memory row just accessed with accumulator and compress; then count records based on pivot for (vector::iterator it = M.V.begin(); it != M.V.end(); it++) V.push_back(*it); LX += M.LX; RE += M.RE; HX += M.HX; sort(V.begin(), V.end(), RecordSort1); M.Empty(K); // compress int Wr = 2*K-1; for (int Rd = 2*K-1; --Rd >= 0; ) if (!V[Wr].k.mink() && !V[Wr].k.maxk() && V[Wr].k == V[Rd].k) { V[Wr].Value += V[Rd].Value; V[Wr].Sequence = min(V[Wr].Sequence, V[Rd].Sequence); RE--; LX++; } else V[--Wr] = V[Rd]; while (--Wr >= 0) V[Wr].Flag(MINKEY); LT = 0, GE = 0; for (int i = 0; i < RE; i++) if (V[LX+i].k < p) LT++; else GE++; if (Op%100 == Mm && RE > K) double pi=123; if (RE != LT+GE) double pi=3.12; } // move all data to one place // changes Acc width from 2K to K void ALU2Easy(Register &M, int K) { int l = min(LX, K-RE); int h = min(HX, K-RE-l); for (int i = 0; i < l; i++) M.V[i].Flag(MINKEY); for (int i = 0; i < RE; i++) M.V[l+i] = V[LX+i]; for (int i = 0; i < h; i++) M.V[l+RE+i].Flag(MAXKEY); M.SetMeta(l, RE, h); SetMeta(K, 0, 0); V.resize(K); for (int i = 0; i < LX; i++) V[i].Flag(MINKEY); } // send data to both memory and acc // changes Acc width from 2K to K void ALU2Dup(Register &M, int K) { ALU2Easy(M, K); for (int i = 0; i < M.LX; i++) V[i].Flag(MINKEY); for (int i = 0; i < M.RE; i++) { V[M.LX+i] = M.V[M.LX+i]; /*V[M.LX+i].k.Transpose();*/ } for (int i = 0; i < M.HX; i++) V[M.LX+M.RE+i].Flag(MAXKEY); SetMeta(M.LX, M.RE, M.HX); } // send data to both memory and acc // changes Acc width from 2K to K void ALU2Trn(Register &M, int K) { ALU2Easy(M, K); for (int i = 0; i < M.LX; i++) V[i].Flag(MINKEY); for (int i = 0; i < M.RE; i++) { V[M.LX+i] = M.V[M.LX+i]; V[M.LX+i].k.Transpose(); } for (int i = 0; i < M.HX; i++) V[M.LX+M.RE+i].Flag(MAXKEY); SetMeta(M.LX, M.RE, M.HX); } void SelfMove(int To, int From, int N) { if (To < From) for (int i = 0; i < N; i++) V[To+i] = V[From+i]; else for (int i = N; --i >= 0; ) V[To+i] = V[From+i]; } void DualMove(int To, Register &M, int From, int N) { for (int i = 0; i < N; i++) V[To++] = M.V[From++]; } // keep NumAcc records in the accumulator; rest to memory // if AccLow, accumulator gets the smallest records // change Acc width from 2K to K void ALU2(int AccLow, int lc, int hc, int LT, Register &M, int NumAcc, int K) { int NumMem = RE-NumAcc; M.Empty(K); #if SORTOPTION == 1 if (hc || lc) { //if (LT > 1) sort(&V[LX], &V[LX+LT-1], RecordSort3); //if (RE-LT > 1) sort(&V[LX+LT], &V[LX+RE-1], RecordSort3); if (LT > 1) sort(&V[LX], &V[LX+LT-1], RecordSort2); if (RE-LT > 1) sort(&V[LX+LT], &V[LX+RE-1], RecordSort2); } #elif SORTOPTION == 2 if (hc || lc) { int GE = RE-LT; if (LT > 1) for (int i = 1; i < LT; i++) { int r = myrand()%LT; Record t = V[LX+r]; V[LX+r] = V[LX+i]; V[LX+i] = t; } if (GE > 1) for (int i = 1; i < GE; i++) { int r = myrand()%GE; Record t = V[LX+LT+r]; V[LX+LT+r] = V[LX+LT+i]; V[LX+LT+i] = t; } } #endif // rotate all the real records to their proper place int shift = 2*K - LX - (AccLow ? NumAcc-K : NumMem) ; shift %= 2*K; int From, To; // Acc to Mem; never an overlapping move if (AccLow) { From = (3*K-shift)%(2*K); To = 0; M.SetMeta(0, NumMem, K-NumMem); } else { From = (K-NumMem+3*K-shift)%(2*K); To = K-NumMem; M.SetMeta(K-NumMem, NumMem, 0); } M.DualMove(To, *this, From, NumMem); // Acc to Acc; might overlap if (AccLow) SetMeta(K-NumAcc, NumAcc, 0); else SetMeta(0, NumAcc, K-NumAcc); SelfMove(LX, (4*K+LX-shift) % (2*K), RE); Meta(); M.Meta(); V.resize(K); #if SORTOPTION == 1 if (hc || lc) { sort(V.begin(), V.end(), RecordSort1); sort(M.V.begin(), M.V.end(), RecordSort1); } #elif SORTOPTION == 2 if (hc || lc) { sort(V.begin(), V.end(), RecordSort1); sort(M.V.begin(), M.V.end(), RecordSort1); } #endif } }; class MergeRow: public TreeRow { friend class DataPath; public: Register Records; private: Key pivot; // -1 value is flag that this row is unused AB first; // do A or B first (depends on function) public: GenState Gs; // state of the generator's state variable public: void Init(int K) { TreeRow::Init(); Records.Empty(K); pivot.SetIndex1(-1); // Not allocated goal = 0; } Key Pivot() { return pivot; } int SubtreeSiz() { return NumA() + Records.Size() + NumB(); } Key Mn() { return mink(MinA(), Records.MinKey()); } Key Mx() { return maxk(Records.MaxKey(), MaxB()); } AB First() { return first; } }; #define STACKUNDERRUN -2 enum step { S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5, S6 = 6, S7 = 7, S8 = 8, S9 = 9, s0 = 10, AY = 0x7fffffff, NX = 0x80000000, }; //#define H 9999 // an out of range step number class Row: public MergeRow { public: step Step; // number of steps completed in a row's multi-step function int ReturnRow; // this is a return address in the equivalent of the stack Opcodes ReturnOpcode; // this is the function to execute on THIS ROW when the subroutine returns int Check; // check flag void Init(int K) { MergeRow::Init(K); Step = S0; Gs.Init(); ReturnRow = STACKUNDERRUN; ReturnOpcode = Opcodes(0); Check = 0; } }; class DataPath { public: vector DRAM; // this models the D.DRAM Register Acc; // This is the "accumulator," used for passing variables Row *ORow; // pointer to the "open" row unsigned LT, GE; // values less-than and greater-than-or-equal to the pivot GenState SK; // if generation is accepted, skip this many records next time int DOp[15]; Row *Read(int a) { return ORow = &DRAM[a]; } void Network(Opcodes O, unsigned K, Scalars Arg, int rn, int dbgstep, ServeData *qx, FILE *index); void DataOp(Vars code, int, int, Opcodes, ServeData *, FILE *Index); }; // Data records: Acc and memory row (ORow->Records), each 0..K records. K is a static parameter // Key value: pivot // Following sizes, each an integer 0..K: InpSiz Acc size at beginning of step, // LT and GE are number of records whose keys are less than and greater-than-or-equal to the pivot, after compression // goal: set in one of two places depending on opcode void DataPath::Network(Opcodes Opcode, unsigned K, Scalars Arg, int dbgrow, int dbgstep, ServeData *qx, FILE *Index) { MergeRow *ORow = DataPath::ORow; int InpSiz = Acc.Size(); #if SNCODE if (Acc.Size() > 0 && ORow->Records.Size() > 0) SN.RunSortNetwork(Acc.Raw(), ORow->Records.Raw(), K, SNWLEN, qx, Index); #endif if (Opcode == Mm) if (ORow->Records.RE > 0) { ORow->Gs.Init(ORow->Records.V[ORow->Records.LX].k, ORow->Records.V[ORow->Records.LX+ORow->Records.RE-1].k); if (0) if (MMTRACE) fprintf(Index, "Mm (%d) init-------------|Acc|=%d |Mem|=%d (%d,%d)-(%d,%d)-(%d,%d) off=%d\n", dbgrow, Acc.HowMany(), ORow->Records.HowMany(), ORow->Gs.LowK.i(), ORow->Gs.LowK.j(), ORow->Gs.ScanK.i(), ORow->Gs.ScanK.j(), ORow->Gs.HighK.i(), ORow->Gs.HighK.j(), ORow->Gs.OFFSET); } else ORow->Gs.Init(); if (Opcode%100 != Mm) Acc.ALU1(ORow->Records, LT, GE, ORow->pivot, K, Opcode); else SK = Acc.ALU1x(ORow->Records, DataPath::ORow->Gs, Arg.Max(), dbgrow, Opcode, dbgstep, K, 1, qx, Index); // merge memory row just accessed with accumulator and compress; then count records based on pivot // data path variable count options // these variables are used during normalize function and ignored otherwise if (Opcode == Nm) { ORow->goal = (ORow->ADat.SzGl()+LT) % K; if (ORow->goal == 0 && ORow->ADat.SzGl()+LT >= (unsigned)K) ORow->goal += K; #if 1 // set preference, but don't force this row to be empty switch (NormStrategy) { case 0: ORow->goal = 0; if (ORow->BDat.SzGl()+GE < K) ORow->goal = K - (ORow->BDat.SzGl()+GE); break; case 999: ORow->goal = K; if (ORow->ADat.SzGl()+LT < K) ORow->goal = ORow->ADat.SzGl()+LT; break; default: break; } #endif ORow->first = ORow->goal+GE <= K ? A : B; } // these variables are used during maximum and minimum and ignored otherwise if (Opcode == Mx || Opcode == Mn) ORow->goal = Arg.SzGl(); DOp[LPV] = min(LT, K); // send smallest records, but no more than K DOp[HPV] = min(GE, K); // send largest records, but no more than K // these variables are used during addvec and ignored otherwise DOp[LPG] = LT-ORow->Goal(); // the number of small records beyond the goal DOp[HPG] = GE-(K-ORow->Goal()); // the number of large records beyong the goal // second part of max and min; ... DOp[LIX] = max(unsigned(InpSiz), min(LT, unsigned(ORow->goal))); DOp[HIX] = max(unsigned(InpSiz), min(GE, unsigned(ORow->goal))); DOp[LAA] = DOp[LBB] = InpSiz; // send as many records as were received as input DOp[LSC] = DOp[HSC] = min(int(LT+GE), ORow->goal); // reply to caller with as much as requested, but no more than we have } // data assumed to be in Acc as a double-length register // this function may: // set the pivot // zero memory // move data, specifically divide Acc into two parts and move one part to memory // on subtree operations, update tree sizes in current row void DataPath::DataOp(Vars code, int K, int InpSiz, Opcodes Op, ServeData *qx, FILE *Index) { int v; switch (code) { case NPV: if (ORow->pivot.ij() == -1) ORow->pivot = Acc.FindPvt(); Acc.ALU2Easy(ORow->Records, K); // complete second part if (Op%100 == Mm && ORow->Records.V[0].Value == 0) double pi=3.14; return; case ZRM: Acc.ALU2Easy(ORow->Records, K); // complete second part ORow->Init(K); return; case DUP: Acc.ALU2Dup(ORow->Records, K); // complete second part return; case TRN: Acc.ALU2Trn(ORow->Records, K); // complete second part return; case GEN: { int i1 = SK.OFFSET; int i2 = ORow->Gs.OFFSET; //ORow->Gs.ScanK; ORow->Gs = SK; //if (MMTRACE) printf("GEN*********************\n"); if (MMTRACE) fprintf(Index, "%s>GEN%s%s[%d,%d]+%s%s\n", NO1, NO2, NO1, ORow->Gs.ScanK.i(), ORow->Gs.ScanK.j(), ORow->Gs.OFFSET==0x7fffffff?"inf":SISuffix(ORow->Gs.OFFSET), NO2); //ORow->Gs.Block; } if (ORow->Records.V[0].Value == 0) double pi=13; return; case ZRA: Acc.SetMeta(K, 0, 0); Acc.Meta(); if (MMTRACE) fprintf(Index, "%s>ZRA%s%s[%d,%d]+%s%s\n", NO1, NO2, NO1, ORow->Gs.ScanK.i(), ORow->Gs.ScanK.j(), ORow->Gs.OFFSET==0x7fffffff?"inf":SISuffix(ORow->Gs.OFFSET), NO2); //if (MMTRACE) printf("ZRA*********************\n"); return; case LIX: v = max(unsigned(InpSiz), min(LT, unsigned(ORow->goal))); break; case HIX: v = max(unsigned(InpSiz), min(GE, unsigned(ORow->goal))); break; case LPV: v = min(int(LT), K); break; case HPV: v = min(int(GE), K); break; case LPG: v = LT-ORow->Goal(); break; case HPG: v = GE-(K-ORow->Goal()); break; case LAA: case LBB: v = InpSiz; break; case LSC: case HSC: v = min(int(LT+GE), ORow->goal); break; default: v = -1; ASSERT(0); } if (Op%100 == Mm && ORow->Records.V[0].Value == 0) double pi=3.14; if (v != DOp[code]) double pi=3.14; int NumToVec = DOp[code]; Acc.ALU2(codeRecords, NumToVec, K); } #define T__ 15 // always true #define CAA 1 // A subtree exists #define CBB 2 // B subtree exists #define CSA 12 // Start on A side #define CSB 9 // Start on B side #define CGI 14 // Goal greater than input #define CGD 13 // Goal greater than data #define CGL 20 // #define CGH 21 // #define CGG 11 // Goal greater than zero #define CKG 10 // K-Goal greater than zero #define CRE 3 // not processing last row of dram #define CRB 4 // processing first row of dram #define CNP 5 // pivot is not set #define CKL 6 // row is not full #define CLL 7 // more records below pivot than above #define CHH 22 // more records below pivot than above #define ALT 23 // alternate true/false #define FRA 24 // from subtree A #define FRB 25 // from subtree B #define FRP 26 // from parent #define FIA 27 // key to find is in the A subtree, looking for specific element #define FIB 28 // key to find is in the B subtree, looking for specific element #define SUA 29 // key to find is in the A subtree, looking for successor to key #define SUB 30 // key to find is in the B subtree, looking for successor to key #define GFB 31 // generate condition, fetch before last #define NUMCOND 32 // necessary size of array (one more than max index) #define ZR 0 // pass zero #define GL 1 // pass our goal #define LG 2 // pass K-goal (goal spelled backwards) #define SZ 3 // pass size of subtree #define EL 6 // arg will be left, self, right #define EP 7 // EL and print #define LK 8 // pass lowest key #define LL 9 // pass lowest and highest key #define LM 10 // pass lowest key #define A_ 4 // pass nothing (error if recipient uses this value) #define A_ILLEGALVALUE 0x80000000 #define CtlBlkSiz 46 struct SsCommand { Opcodes C_Op; // function to call step C_Step; // step trigger condition (or H if no stepping) int C_X; // opcode as member of enum, use mod 100 int C_Y; // integer condition int C_Z; // integer condition AB A_AB; // side char A_Fcn; // character control code Opcodes A_Op; // call opcode step A_Step; // step trigger condition (or H if no stepping) Vars A_D; // data path control int A_Argv; // argument passed to next instruction char *Color; char *Comment; } ControlBlock[CtlBlkSiz] = { { Nm, S0, CSA, CAA, CGG, A, 'C', Mx, NX, NPV, GL, "blue", "Code below needs to do the functions A B C D E F, but they may need to be ordered C D A B E F to avoid an overflow condition. Therefore, the code is structured as if (OK) { A B } C D if (!OK) { A B } E F, where OK is row->Goal+GE <= K and indicates no overflow. Find maximum elements in A subtree, unless A subtree does not exist or if we don't need anything from it. Also, skip until later if Acc would overflow -- see documentation." }, { Nm, S1, CSA, CGL, T__, A, 'C', Aw, NX, LPG, A_, "blue", "Send excess records from max back to subtree with Addvc. Also, skip until later if Acc would overflow -- see documentation." }, { Nm, S2, CBB, CKG, T__, B, 'C', Mn, NX, NPV, LG, "blue", "Find minimum elements in B subtree, unless B subtree does not exist or if we don't need anything from it." }, { Nm, S3, CGH, T__, T__, B, 'C', Aw, NX, HPG, A_, "blue", "Send excess records from max back to subtree with Addvc." }, { Nm, S4, CSB, CAA, CGG, A, 'C', Mx, NX, NPV, GL, "blue", "Find maximum elements in A subtree, unless A subtree does not exist or if we don't need anything from it. Also, this is the retry, given reordering to avoid overflow -- see documentation." }, { Nm, S5, CSB, CGL, T__, A, 'C', Aw, NX, LPG, A_, "blue", "Send excess records from max back to subtree with Addvc. also, this is the retry, given reordering to avoid overflow -- see documentation." }, { Nm, S6, CAA, T__, T__, A, 'C', Nm, NX, NPV, A_, "blue", "Recursively normalize A side, unless subtree A does not exist." }, { Nm, S7, CBB, T__, T__, B, 'C', Nm, NX, NPV, A_, "blue", "Recursively normalize B side, unless subtree B does not exist." }, { Nm, AY, T__, T__, T__, U, 'R', N_, NX, NPV, SZ, "blue", "Return size of subtree." }, // 9 { Mx, AY, CGI, CBB, T__, B, 'C', Mx, NX, LBB, GL, "green", "Pull from right side while the complete caller's request has not been validated yet and there is a right subtree." }, { Mx, AY, CGD, CAA, T__, A, 'C', Mx, NX, HIX, GL, "green", "If there is no left subtree, the LT part of the row will be minimal. Pull from left side while the complete caller's request has not been validated yet and there is a left subtree." }, { Mx, AY, T__, T__, T__, U, 'r', N_, NX, HSC, SZ, "green", "When there are no subtrees, the entire row is minimal." }, // 12 { Mn, AY, CGI, CAA, T__, A, 'C', Mn, NX, LAA, GL, "red", "Pull from left side while the complete caller's request has not been validated yet and there is a left subtree." }, { Mn, AY, CGD, CBB, T__, B, 'C', Mn, NX, LIX, GL, "red", "If there is no left subtree, the LT part of the row will be minimal. Pull from right side while the complete caller's request has not been validated yet and there is a right subtree." }, { Mn, AY, T__, T__, T__, U, 'r', N_, NX, LSC, SZ, "red", "When there are no subtrees, the entire row is minimal." }, // 15 { Cl, AY, CRB, T__, T__, N, 'J', Cl, NX, ZRM, A_, "purple", "First row." }, { Cl, AY, CRE, T__, T__, N, 'J', Cl, NX, ZRM, A_, "purple", "All intermediate rows." }, { Cl, AY, T__, T__, T__, N, 'R', N_, NX, ZRM, ZR, "purple", "Last row." }, // 18 { Av, AY, CNP, T__, T__, U, 'R', N_, NX, NPV, A_, "orange", "This could be initial addition to the root node, or first use of a leaf node. It may be assumed to have been initialized." }, { Av, AY, CKL, T__, T__, U, 'R', N_, NX, NPV, A_, "orange", "Even with additional records, still fits in a row." }, { Av, AY, CAA, CLL, T__, A, 'J', Av, NX, LPV, A_, "orange", "There are more of the smaller values. Vec { passdown values | keep values , \"\" }." }, { Av, AY, CBB, CHH, T__, B, 'J', Av, NX, HPV, A_, "orange", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, #if READDVEC == 1 { Av, AY, ALT, CLL, T__, A, 'J', Av, NX, LPV, A_, "orange", "There are more of the smaller values. Vec { passdown values | keep values , \"\" }." }, { Av, AY, ALT, CHH, T__, B, 'J', Av, NX, HPV, A_, "orange", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, #else { Av, AY, T__, CLL, T__, A, 'J', Av, NX, LPV, A_, "orange", "There are more of the smaller values. Vec { passdown values | keep values , \"\" }." }, { Av, AY, T__, CHH, T__, B, 'J', Av, NX, HPV, A_, "orange", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, #endif { Av, AY, T__, CLL, T__, Z, 'J', Aw, NX, LPV, A_, "orange", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, { Av, AY, T__, CHH, T__, Z, 'J', Aw, NX, HPV, A_, "orange", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, // 26 { Aw, AY, CNP, T__, T__, U, 'R', N_, NX, NPV, A_, "pink", "This could be initial addition to the root node, or first use of a leaf node. It may be assumed to have been initialized." }, { Aw, AY, CKL, T__, T__, U, 'R', N_, NX, NPV, A_, "pink", "Even with additional records, still fits in a row." }, { Aw, AY, CLL, T__, T__, A, 'J', Aw, NX, LPV, A_, "pink", "There are more of the smaller values. Vec { passdown values | keep values , \"\" }." }, { Aw, AY, T__, T__, T__, B, 'J', Aw, NX, HPV, A_, "pink", "There are more of the larger values. Vec { keep values | passdown values , \"\" }." }, // 30 { Sp, S0, CAA, T__, T__, A, 'C', Sp, NX, NPV, A_, "Navy", "Recursively explore A side, unless subtree A does not exist." }, #if YTRANSPOSE==1 { Sp, S1, T__, T__, T__, Y, 'C', Av, NX, TRN, GL, "Navy", "Duplicate and transpose data and addvec to the alternate tree." }, #else { Sp, S1, T__, T__, T__, Y, 'C', Av, NX, DUP, GL, "Navy", "Duplicate data and addvec to the alternate tree." }, #endif { Sp, S2, CBB, T__, T__, B, 'C', Sp, NX, NPV, A_, "Navy", "Recursively explore B side, unless subtree B does not exist." }, { Sp, AY, T__, T__, T__, U, 'R', N_, NX, NPV, SZ, "Navy", "Return size of subtree." }, // 34: X(3) = Y(2) * Z(1) { Fi, AY, CAA, FIA, SUA, A, 'J', Fi, NX, NPV, LM, "#4B0082", "Recursively explore A side, unless subtree A does not exist." }, { Fi, AY, CAA, FIA, T__, A, 'J', Fi, NX, NPV, LL, "#4B0082", "Recursively explore A side, unless subtree A does not exist." }, { Fi, AY, CBB, FIB, T__, B, 'J', Fi, NX, NPV, LL, "#4B0082", "Recursively explore B side, unless subtree B does not exist." }, { Fi, AY, SUB, T__, T__, U, 'R', N_, NX, DUP, LM, "#4B0082", "Return duplicate of memory." }, { Fi, AY, T__, T__, T__, U, 'R', N_, NX, DUP, LL, "#4B0082", "Return duplicate of memory." }, // 39 walking Yt(k, i), data from Z(k, j), result in X(i, j) { Mm, S0, CAA, T__, T__, A, 'C', Mm, NX, ZRA, A_, "Asparagus", "Recurse to A." }, { Mm, S1, T__, GFB, T__, Z, 'C', Fi, S3, ZRA, LK, "Asparagus", "Find next key in Z, repeat." }, { Mm, S2, T__, T__, T__, Z, 'C', Fi, S4, ZRA, LK, "Asparagus", "Find next key in Z." }, { Mm, S3, T__, T__, T__, X, 'C', Av, S1, GEN, A_, "Asparagus", "Generate product; Av to X, repeat." }, { Mm, S4, T__, T__, T__, X, 'C', Av, NX, GEN, A_, "Asparagus", "Generate product; Av to X." }, { Mm, S5, CBB, T__, T__, B, 'C', Mm, NX, ZRA, A_, "Asparagus", "Recurse to B." }, { Mm, S6, T__, T__, T__, U, 'R', N_, NX, ZRA, SZ, "Asparagus", "Return." }, }; class Superstrider: public DataPath { public: int PreviousRow, RowNumQ; int RowNum; int PendingPop; int PendingCall; Opcodes Op; int ReturnRow; int FreeMeFlag; // if set, indicates that the child node requests it be freed upon return int FreeListRow; // these variables control memory allocation in the DRAM Scalars Arg; // integer argument or return value unsigned CycleCount; int COND[NUMCOND]; char *CONDTXT[NUMCOND]; Row *rrow; int Verify(int RowNum) { Row &row = DRAM[RowNum]; int lv = row.IsA() ? Verify(row.RowA()) : 0; int rv = row.IsB() ? Verify(row.RowB()) : 0; if (lv < 0 || rv < 0) return -1; if (lv != row.NumA()) return -1; if (rv != row.NumB()) return -1; return lv + row.Records.Size() + rv; } void PrintAcc(const char *txt, Register *, ServeData *qx, FILE *index); void PrintRowTree(int RowNum, int Indent, map &GroundTruth, ServeData *qx, FILE *index); void Print(const char *txt, int root, Register *, int IndentFlag, int Trace, unsigned K, map &GroundTruth, ServeData *qx, FILE *index); int Eff2(int RowNum) { int rval = 1; Row &row = DRAM[RowNum]; if (row.IsA()) rval += Eff2(row.RowA()); if (row.IsB()) rval += Eff2(row.RowB()); return rval; } double Efficiency(int root, unsigned K, vector > &GroundTruth2) { int Resources = 0, gt = 0; //for (unsigned i = 0; i < GroundTruth2.size(); i++) int i = root; { gt += GroundTruth2[i].size(); Resources += Eff2(i); } return 1.*gt/(K*Resources); } int Spider(int row, int Mark) { if (row == -1) return 0; if (row < 0 || row >= int(DRAM.size())) return 1; int ErrCnt = 0; Row *r = &DRAM[row]; if (r->Check != 0) ErrCnt++; r->Check = Mark; if (r->rowA && Spider(r->rowA, Mark)) ErrCnt++; if (r->rowB && Spider(r->rowB, Mark)) ErrCnt++; return ErrCnt; } int Analyze(int ReturnRow) { // check stack structure for (int Tmp = 0; Tmp < int(DRAM.size()); Tmp++) DRAM[Tmp].Check = 0; int ErrCnt = 0, Addr = ReturnRow, i; if (ReturnRow != -1) { // mark valid return addresses in memory by adding the DRAM size, except -1 for (i = 0; i < int(2*DRAM.size()); i++) { Row *row = &DRAM[Addr]; Addr = row->ReturnRow; if (Addr == -1) break; if (Addr < 0 || Addr >= int(DRAM.size())) ErrCnt++; row->Check = 1; } if (i == 2*DRAM.size()) ErrCnt++; } ASSERT(ErrCnt == 0); for (Addr = 0; Addr < int(DRAM.size()); Addr++) { Row *row = &DRAM[Addr]; // check memory for STACKUNDERRUN, -1, or marked return addresses int row2 = row->ReturnRow; if (row2 == -1) ; else if (row2 == STACKUNDERRUN) ; else if (row->Check) ; else ErrCnt++; // check memory for cleared step if (row2 == STACKUNDERRUN && Addr != RowNum && row->Step != 0) ErrCnt++; } ASSERT(ErrCnt == 0); for (int Tmp = 0; Tmp < int(DRAM.size()); Tmp++) DRAM[Tmp].Check = 0; if (Spider(FreeListRow, 1)) ErrCnt++; for (int i = 0; i < ROOTS; i++) if (Spider(i, i+2)) ErrCnt++; for (int Tmp = 0; Tmp < int(DRAM.size()); Tmp++) { if (DRAM[Tmp].Check == 0) ErrCnt++; else if (DRAM[Tmp].Check == 1) ; else ; } ASSERT(ErrCnt == 0); for (int Tmp = 0; Tmp < int(DRAM.size()); Tmp++) DRAM[Tmp].Check = 0; ASSERT(ErrCnt == 0); return ErrCnt; } void Action(SsCommand &tab, int, int, ServeData *, FILE *Index); int StateMachine(Opcodes O, int Rn, unsigned K, ServeData *, FILE *Index); } S; void TreeRow::AllocAB(int &rowAB, Superstrider *s, int K) { if (rowAB != 0) return; rowAB = s->FreeListRow; Row &row = s->DRAM[rowAB]; s->FreeListRow = row.RowA(); row.Init(K); } void TreeRow::FreeAB(int &rowAB, Superstrider *s, int K) { Row &row = S.DRAM[rowAB]; ASSERT(row.RowA() == 0); ASSERT(row.RowB() == 0); row.Init(K); row.SetRowA(s->FreeListRow); s->FreeListRow = rowAB; rowAB = 0; } // print accumulator only void Superstrider::PrintAcc(const char *txt, Register *w, ServeData *qx, FILE *index) { const char *NOut1 = ""; const char *NOut2 = ""; fprintf(index, "%s%s%s", NOut1, txt, NOut2); for (unsigned pos = 0; pos < w->Size(); pos++) { //for (vector::iterator it = Acc->begin(); it != Acc->end(); it++) { //fprintf(index, "%s[%d]=%4.2f%s", "\"#E6E6FA\"", NOut1, it->Index, it->Value, NOut2); fprintf(index, "%s[%d]=%s%s", "\"#E6E6FA\"", NOut1, w->Access(pos).k.ij(), SISuffix(w->Access(pos).Value), NOut2); //fprintf(index, "%s[%d]=%s%s", "\"#E6E6FA\"", NOut1, w->Access(pos).Index, SISuffix(w->Access(pos).Sequence), NOut2); } fprintf(index, "\n"); } // to suppress indenting, provide a large negative value for the parameter Intent void Superstrider::PrintRowTree(int RowNum, int Indent, map &GroundTruth, ServeData *qx, FILE *index) { const char *NOut1 = ""; const char *NOut2 = ""; Row &row = DRAM[RowNum]; if (row.IsA()) PrintRowTree(row.RowA(), Indent+1, GroundTruth, qx, index); fprintf(index, ""); #if RANGEINHTML == 0 fprintf(index, //"%s%d:(%d)%s" "%s%d%s%s%d(%d)%s%s%d(%d)%s", //NOut1, RowNum, Verify(RowNum), NOut2, NOut1, row.Pivot().ij(), NOut2, NOut1, row.RowA(), row.NumA(), NOut2, NOut1, row.RowB(), row.NumB(), NOut2); #else int loe = row.MaxA() > row.Records.MinKey() || row.MaxA() == row.Records.MinKey(); int hie = row.Records.MaxKey() > row.MinB() || row.Records.MaxKey() == row.MinB(); fprintf(index, "%s%d:
%d-%d#%d%s" "%s%d(%d)
%s..%s%s" "%s%d(%d)
%s..%s%s", NOut1, RowNum, row.Records.MinKey().ij(), row.Records.MaxKey().ij(), row.Pivot().ij(), NOut2, loe ? " bgcolor=gray" : "", NOut1, row.RowA(), row.NumA(), row.MinA().maxk()?"inf":SISuffix(row.MinA().ij(), 3, 0), row.MaxA().mink()?"-inf":SISuffix(row.MaxA().ij(), 3, 0), NOut2, hie ? " bgcolor=gray" : "", NOut1, row.RowB(), row.NumB(), row.MinB().maxk()?"inf":SISuffix(row.MinB().ij(), 3, 0), row.MaxB().mink()?"-inf":SISuffix(row.MaxB().ij(), 3, 0), NOut2); #endif for (int i = 0; i < Indent; i++) fprintf(index, ""); for (unsigned pos = 0; pos < row.Records.Size(); pos++) { Record &r = row.Records.Access(pos); const char *color; if (GroundTruth.find(r.k) != GroundTruth.end()) { double ratio = 1.; double val1 = GroundTruth[r.k]; double val2 = r.Value; if (fabs(val1) > 1e-9 && fabs(val2) > 1e-9) { ratio = val1/val2; if (ratio < 1.) ratio = val2/val1; } if (ratio > 1.0000001) color = "yellow"; else if (r.k < row.Pivot()) color = "#FF5C5C"; else color = "#A7FC00"; } else color = "grey"; //fprintf(index, "%s[%d]=%4.2f%s", color, NOut1, it->Index, it->Value, NOut2); if (color[0] == 'y') fprintf(index, "%s[%d,%d]=%s %s%s", color, NOut1, r.k.i(), r.k.j(), SISuffix(r.Value), SISuffix(GroundTruth[r.k]), NOut2); else fprintf(index, "%s[%d,%d]=%s%s", color, NOut1, r.k.i(), r.k.j(), SISuffix(r.Value), NOut2); //fprintf(index, "%s[%d]=%s%s", color, NOut1, r.Index, SISuffix(r.Sequence), NOut2); } fprintf(index, "\n"); if (row.IsB()) PrintRowTree(row.RowB(), Indent+1, GroundTruth, qx, index); qx->IncrementalWrite(); } void Superstrider::Print(const char *txt, int root, Register *w, int IndentFlag, int Trace, unsigned K, map &GroundTruth, ServeData *qx, FILE *index) { const char *NOut1 = ""; const char *NOut2 = ""; int gt = GroundTruth.size(); int vf = Verify(root); const char *fmt = gt==vf ? "" : " bgcolor=orange"; if (gt != vf) double pi=3.12; fprintf(index, "" //"" "\n", fmt, //NOut1, NOut2, NOut1, NOut2, NOut1, NOut2, NOut1, NOut2, NOut1, gt, vf, txt, NOut2); if (w != 0) PrintAcc("Acc", w, qx, index); PrintRowTree(root, IndentFlag == 0 ? -10000: 0, GroundTruth, qx, index); fprintf(index, "
%sAddr:(size)%s%sPivot%s%sAddr(size)%s%sAddr(size)%s%s%d %d %s%s
"); qx->IncrementalWrite(); } enum FROM { PARENT, CHILDA, CHILDB, UNKNOWN, }; static int seed = 0; #define CNDLIST \ CND(T__, TRUE) \ CND(CAA, row->IsA()) \ CND(CBB, row->IsB()) \ CND(CSA, row->First()==A) \ CND(CSB, row->First()==B) \ CND(CGI, row->Goal()>InpSiz) \ CND(CGD, row->Goal()>DOp[LIX]) \ CND(CGL, DOp[LPG]>0) \ CND(CGH, DOp[HPG]>0) \ CND(CGG, row->IsA() && row->Goal()>0 && (DISABLENMOPTIMIZATION || row->Goal()>int(LT) || !(row->MaxA()Goal()>0 && (DISABLENMOPTIMIZATION || K-row->Goal()>int(GE) || !(row->MinB()>Acc.MaxKey()))) \ CND(CRE, int(DRAM.size())-1>RowNum) \ CND(CRB, RowNumPivot().unik()) \ CND(CKL, K>=LT+GE) \ CND(CLL, LT>=GE) \ CND(CHH, LTMaxA() || Arg.Min() == ORow->MaxA()) \ CND(FIB, Acc.RE == 0 ? 0 : Arg.Min() > Acc.V[Acc.LX+Acc.RE-1].k) /* try B side if result definitely not in the buffer */ \ CND(SUA, Acc.RE == 0 ? 0 : Arg.Max() > Acc.V[Acc.LX].k || Arg.Max() == Acc.V[Acc.LX].k) /* end of the block may be in the register */ \ CND(SUB, Arg.Max() > ORow->MinB() || Arg.Max() == ORow->MinB()) /* end of the block may be in the register */ \ CND(GFB, row->Gs.OFFSET<0x7ffffff) #define ARGLIST \ ARG(ZR, (ZerKey(), 0, ZerKey(), 0)) \ ARG(GL, (ZerKey(), row->Goal(), ZerKey(), 0)) \ ARG(LG, (ZerKey(), K-row->Goal(), ZerKey(), 0)) \ ARG(SZ, (row->Mn(),row->SubtreeSiz(),row->Mx(),0)) \ ARG(EL, (ZerKey(), CurRow, ZerKey(), 0)) \ ARG(EP, (ZerKey(), CurRow, ZerKey(), 1)) \ ARG(LK, (MnKey, NoArg, MxKey, 0)) \ ARG(LL, (MnKey2, NoArg, MxKey2, 0)) \ ARG(LM, (MnKey2, NoArg, ZerKey(), 0)) \ ARG(A_, (ZerKey(), NoArg, ZerKey(), 0)) void Superstrider::Action(SsCommand &tab, int K, int InpSiz, ServeData *qx, FILE *Index) { Row *row = ORow; #if 0 row->Step = step(tab.C_Step == AY ? 0 : tab.C_Step + 1); #else if (tab.C_Step == AY) row->Step = step(0); else if (tab.A_Step == NX) row->Step = step(tab.C_Step + 1); else row->Step = step(tab.A_Step); #endif // 1. Manage the data path DataOp(tab.A_D, K, InpSiz, Op, qx, Index); if (tab.A_D == LPV && tab.A_AB != X && tab.A_AB != Y && tab.A_AB != Z)// update subtree estimates, but not when jumping to root ORow->SetNumA(Scalars(ZerKey(), ORow->NumA() + DOp[LPV], ZerKey(), 0)); if (tab.A_D == HPV && tab.A_AB != X && tab.A_AB != Y && tab.A_AB != Z)// update subtree estimates, but not when jumping to root ORow->SetNumB(Scalars(ZerKey(), ORow->NumB() + DOp[HPV], ZerKey(), 0)); // 2. Move through the tree or linear space, handling demand creation and subtree size estimates int NextRow = -1; if (tab.A_AB==A) { // descend A side row->AllocA(this, K); // demand create if (tab.A_Fcn != 'J' && Op%100 != Mm) // pre-adjust tree value if a call but not a jump row->SetNumA(Scalars(row->NumA() + DOp[tab.A_D])); NextRow = row->RowA(); // ultimately this is where we go next } else if (tab.A_AB==B) { // descend B side row->AllocB(this, K); // demand create if (tab.A_Fcn != 'J' && Op%100 != Mm) // pre-adjust tree value if a call but not a jump row->SetNumB(Scalars(row->NumB() + DOp[tab.A_D])); NextRow = row->RowB(); // ultimately this is where we go next } else if (tab.A_AB==N) { // linear access for initialization if (RowNumSetRowA(RowNum+1), NextRow = RowNum+1; else row->SetRowA(-1), NextRow = -1; } else if (tab.A_AB==U) { // jump up, better have the parent's row number as the goal if (tab.A_Fcn == 'J') NextRow = row->Goal(); // better be here } else if (tab.A_AB==Z) { // linear access for initialization NextRow = 0; // ultimately this is where we go next } else if (tab.A_AB==Y) { // linear access for initialization NextRow = 1; // ultimately this is where we go next } else if (tab.A_AB==X) { // linear access for initialization NextRow = 2; // ultimately this is where we go next } // 3. On return: Return address is in ReturnRow; set PendingPop to get the next return address // PendingPop provides the next opcode in the caller // Set Arg as needed for the circumstance if (tab.A_Fcn == 'R' || tab.A_Fcn == 'r') { // some form of return, so pop NextRow = ReturnRow; PendingPop = 1; row->Step = S0; /* if (O == Mm) if (row->Records.RE > 0) row->Gs.Init(row->Records.V[row->Records.LX].k, row->Records.V[row->Records.LX+row->Records.RE-1].k); else row->Gs.Init();*/ row->Gs.Init(); if (tab.A_Fcn == 'r') // delete if empty FreeMeFlag = row->RowA() == 0 && row->Records.Size() == 0 && row->RowB() == 0; } // 4. On call: Push ReturnRow and store return address into the available location // on jump, just change opcode // Set arg as needed // Set opcode and ReturnOpcode from table if (tab.A_Fcn == 'C') { // a call, so push ASSERT(row->ReturnRow == STACKUNDERRUN); row->ReturnRow = ReturnRow; ReturnRow = RowNum; row->ReturnOpcode = Opcodes(100 + Op%100); Op = tab.A_Op; } else if (tab.A_Fcn == 'J') { // just change opcode if (Op != tab.A_Op) { static int foo = 0; foo++; double pi=3.12; } Op = tab.A_Op; } // 5. Set row number for next cycle int CurRow = RowNum; RowNum = NextRow; // until block 0 is complete, set to ORow->Records.MinKey() with i index set to 0 // afterwards, set to one more than Acc.MaxKey, unless this wraps or creates an i index beyond the i index of ORow->Records.MaxKey() Key MnKey = ORow->Gs.ScanK; Key MxKey = ORow->Gs.HighK; // this should be the i index with max val j? //Key MnKey2 = ORow->MinA(); Key MnKey2 = Arg.Min(); Key MxKey2 = Arg.Max(); if (tab.C_Op == Fi) double pi=3.14; if (tab.A_Argv == 8) double pi=1234; if (tab.A_Argv == 9) double pi=1234; // 6. Find the scalar data to pass from a table of values Arg = #define NoArg A_ILLEGALVALUE #define ARG(n, cc) tab.A_Argv == n ? Scalars cc : ARGLIST #undef ARG #undef NoArg Scalars(-1); } int Superstrider::StateMachine(Opcodes O, int Rn, unsigned K, ServeData *qx, FILE *Index) { PreviousRow = -1, RowNumQ = -1; RowNum = Rn; PendingPop = 0; PendingCall = 1; // the simulator frameworks "calls" the statemachine, setting return fields and so forth Op = O; ReturnRow = -1; FreeMeFlag = 0; // if set, indicates that the child node requests it be freed upon return while (RowNum != -1) { PreviousRow = RowNumQ; RowNumQ = RowNum; Row *row = rrow = Read(RowNum); CycleCount++; if (CycleCount > MME) MMTRACE = 0; else if (CycleCount >= MMS) MMTRACE = 1; Scalars tArg = Arg; // previous state transition did a return using the variable ReturnRow above // we needed to pop the stack, but couldn't until the row with the right data had been accessed if (PendingPop) { ASSERT(row->ReturnRow != STACKUNDERRUN); ReturnRow = row->ReturnRow; Op = row->ReturnOpcode; row->ReturnRow = STACKUNDERRUN; PendingPop = 0; } // previous state transition did a call to this row // we need to push onto the stack, but couldn't until the row with the right data had been accessed if (PendingCall) { row->Step = S0; /*if (O == Mm) if (row->Records.RE > 0) row->Gs.Init(row->Records.V[row->Records.LX].k, row->Records.V[row->Records.LX+row->Records.RE-1].k); else row->Gs.Init();*/ PendingCall = 0; } if (O != Cl) // avoid checking during clearing period Analyze(ReturnRow); // memory is imagined to be organized as a tree, where each row can have descendant rows // a subroutine can be called on a descendant // the RETURN(op, c) transfers control to the parent, which will be the caller, but... // returns the memory to the freelist if c evaluates to TRUE, also zeroing the pointer in the parent // this feature creates a responsibility if called from outside the state machine: // if StateMachine returns true, the caller is expected to call RowFreeZeroIndex(row->RowB) FROM From = UNKNOWN; if (PreviousRow == row->RowA() && Op >= 100 && Op%100 != Mm && Op%100 != Fi) { From = CHILDA; row->SetNumA(Arg); if (FreeMeFlag) row->FreeA(this, K); } else if (PreviousRow == row->RowB() && Op >= 100 && Op%100 != Mm && Op%100 != Fi) { From = CHILDB; row->SetNumB(Arg); if (FreeMeFlag) row->FreeB(this, K); } FreeMeFlag = 0; const char *Otxt = OpTxt(Op); int InpSiz = Acc.Size(); // used by condition macro and network Network(Op, K, Arg, RowNum, rrow->Step, qx, Index); int ca = Arg.Min() < ORow->MaxA() || Arg.Min() == ORow->MaxA(); int cb = Arg.Min() > ORow->MinB() || Arg.Min() == ORow->MinB(); #define TRUE 1 #define CND(n, c) COND[n] = c; CNDLIST #undef TRUE #undef CND int i = 0; for (i = 0; i < CtlBlkSiz; i++) { SsCommand &tab = ControlBlock[i]; if (Op%100 == tab.C_Op && COND[tab.C_X] && COND[tab.C_Y] && COND[tab.C_Z] && (rrow->Step&0xff) <= tab.C_Step) { //if (0) if (MMTRACE && Op%100 == Fi) fprintf(Index, "%s>Fi: %d.Fi%d.%d%s%s%d %d ca=%d cb=%d A%d B%d%s%s%d %d %d%s\n", NO1, RowNum, i, rrow->Step&0xff, NO2, NO1, Arg.Min().i(), Arg.Min().j(), ca, cb, row->IsA(), row->IsB(), NO2, NO1, COND[FIB], ORow->MinB().i(), ORow->MinB().j(), NO2); /*if (i == 60) { printf("Fi [%d,%d] found row %d: ", tArg.Min().i(), tArg.Min().j(), RowNumQ); for (int i = Acc.LX; i < Acc.LX+Acc.RE; i++) printf("(%d,%d)", Acc.V[i].k.i(), Acc.V[i].k.j()); printf("\n"); }*/ Action(tab, K, InpSiz, qx, Index); if (0) if (MMTRACE && (i==58 || i==59)/*tab.C_Op == Mm*/) fprintf(Index, "Mm (%d) -----------------|Acc|=%d |Mem|=%d (%d,%d)-(%d,%d)-(%d,%d) off=%d\n", RowNumQ, Acc.HowMany(), row->Records.HowMany(), row->Gs.LowK.i(), row->Gs.LowK.j(), row->Gs.ScanK.i(), row->Gs.ScanK.j(), row->Gs.HighK.i(), row->Gs.HighK.j(), ORow->Gs.OFFSET); if (0) if (MMTRACE && (i==56 || i==57)/*tab.C_Op == Mm*/) fprintf(Index, "Mm (%d) +----------------%d.%s (%d,%d)-(%d,%d)\n", RowNumQ, RowNumQ, #define OV(s, n, t) Op == n ? #s : OVLIST "?", #undef OV Arg.Min().i(), Arg.Min().j(), Arg.Max().j(), Arg.Max().j()); //if (tab.C_Op == F1 || tab.C_Op == Fu || tab.C_Op == Fd) //if (tab.C_Op == Mm || tab.C_Op == Fi) //printf("%d: 0x%x: L:0x%x R:0x%x ->0x%x (%d) %d/%d records\n", 999, RowNumQ, row->RowA(), row->RowB(), RowNum, i, Acc.HowMany(), row->Records.HowMany()); //if (tab.C_Op == Fi) //if (i == 49) // printf("%d: 0x%x: (%d,%d)%d %d L:0x%x R:0x%x ->0x%x (%d) %d/%d records\n", 999, RowNumQ, Arg.Min().i(), Arg.Min().j(), ca, cb, row->RowA(), row->RowB(), RowNum, i, Acc.HowMany(), row->Records.HowMany()); /*if (i == 49) { printf("Fi [%d,%d] found row %d: ", tArg.Min().i(), tArg.Min().j(), RowNumQ); for (int i = Acc.LX; i < Acc.LX+Acc.RE; i++) printf("(%d,%d)", Acc.V[i].k.i(), Acc.V[i].k.j()); printf("\n"); }*/ break; } } if (i == CtlBlkSiz) { qx->IncrementalWrite(); double pi=32; ASSERT(0); } qx->IncrementalWrite(); } return FreeMeFlag; } vector > ReadMatrixMarket(const char *fn) { vector > data; FILE *f = fopen(fn, "r"); if (f == 0) return data; { int ch; while ((ch=getc(f)) == '%') while (getc(f) != '\n') ; ungetc(ch, f); } int rmax = 0, cmax = 0, nzs = 0, i, rval; { for (i = 0; i < 10000; i++) if ((rval = fscanf(f, "%d %d %d \n", &rmax, &cmax, &nzs)) == 3) break; if (i == 10000) ASSERT(i != 10000); } data.resize(rmax); for (int i = 0; i < rmax; i++) data[i].resize(cmax); int nz = 0, r, c; double vd; while (fscanf(f, "%d %d %lf\n", &r, &c, &vd) == 3) { r--; c--; nz++; if (r < 0 || r >= rmax || c < 0 || c >= cmax) ASSERT(r >= 0 && r < rmax && c >= 0 && c < cmax); data[r][c] = vd; } if (nz != nzs) ASSERT(nz == nzs); return data; } // generate a matrix void GenMatrix(int Out, int iSiz, int jSiz, map &data, int &Indent, int &Trace, vector > &GroundTruth2, int &Seq, int K, ServeData *qx, FILE *index) { data.empty(); const char *NMOut1 = ""; const char *NMOut2 = ""; if (MATPRT) fprintf(index, "\n", NMOut1, NMOut2); for (int i = 0; i < iSiz; i++) { if (MATPRT) fprintf(index, ""); for (int j = 0; j < jSiz; j++) { int v = (myrand()&7) == 0; if (v != 0) { Record r; r.k.SetIndex2(i, j); if (MATPRT) fprintf(index, "", NMOut1, v, NMOut2); data[r.k] = v; } else fprintf(index, "", NMOut1, NMOut2); } if (MATPRT) fprintf(index, "\n"); } S.Acc.Empty(K); for (int j = 0; j < jSiz; j++) { for (int i = 0; i < iSiz; i++) { Record r; r.k.SetIndex2(i, j); if (data.find(r.k) != data.end()) { r.Value = data[r.k]; r.Sequence = Seq++; GroundTruth2[Out][r.k] = r.Value; S.Acc.AddSort(r, K); } if (S.Acc.HowMany() == K) { S.StateMachine(Av, Out, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(Out, K, GroundTruth2), S.CycleCount/*j*/, Real); // vertical then horizontal if (Trace) S.Print("Addvc", Out, &S.Acc, Indent, Trace, K, GroundTruth2[Out], qx, index); S.Acc.Empty(K); } } } Register &w = S.Acc; S.StateMachine(Av, Out, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(Out, K, GroundTruth2), S.CycleCount/*i*/, Real); // vertical then horizontal if (Trace) S.Print("Addvc", Out, &w, Indent, Trace, K, GroundTruth2[Out], qx, index); } void __stdcall MMAccThread(ServeData *qx) { //Query *qx = (Query *)sd; // Part 1: define variables, default values, and HTML variable names // d for double, i for integer // variable name // default, do not surround with quotes // HTML variable names #if SNCODE #if BIG==2 #define HTMLVARS \ D(AFile, olm500.mtx, a) \ D(BFile, plskz362.mtx, b) \ I(MemRows, 100, fon) \ I(K, 4, foff) \ I(IndexRange, 7, ioff) \ I(Indent, 0, vhi) \ I(Trace, 0, t) #elif BIG==1 #define HTMLVARS \ D(AFile, olm500.mtx, a) \ D(BFile, plskz362.mtx, b) \ I(MemRows, 2, fon) \ I(K, 256, foff) \ I(IndexRange, 4095, ioff) \ I(Indent, 0, vhi) \ I(Trace, 0, t) #elif BIG==0 #define HTMLVARS \ D(AFile, olm500.mtx, a) \ D(BFile, plskz362.mtx, b) \ I(MemRows, 100, fon) \ I(K, 4, foff) \ I(IndexRange, 15, ioff) \ I(Indent, 0, vhi) \ I(Trace, 0, t) #endif #else #define HTMLVARS \ D(AFile, olm500.mtx, a) \ D(BFile, plskz362.mtx, b) \ I(MemRows, 500, fon) \ I(K, 13, foff) \ I(IndexRange, 880, ioff) \ I(Indent, 0, vhi) \ I(Trace, 0, t) #endif #define D(a, b, c) char *a = strdup(#b); double d##a; #define I(a, b, c) int a = b; HTMLVARS #undef D #undef I // Part 2: Parse input (no specific programmer involvement here) int cmd = -1; // process input, if any if (1) for (int i = 0; i < qx->argc; i++) { char *n = qx->name[i]; char *v = qx->value[i]; if (0) ; #define D(a, b, c) else if (strcmp(n, #c) == 0) qx->SS(a, v), qx->SD(d##a, v); #define I(a, b, c) else if (strcmp(n, #c) == 0) qx->SI(a, v); HTMLVARS #undef D #undef I else if (strcmp(n, "cmd") == 0) cmd = 0; } // print the header FILE *index = qx->TitleTextOpenBufferFile("Status Page", "test", "htm", 0, NULL); #if FANCYPAGE != 0 FancyPageBegin(index, *qx); #else fprintf(Index, "Fancy Page Stub
\n"); #endif // Part 3: Do entity encoding as needed (no specific programmer involvement here) #define D(a, b, c) char *encoded_##a = EntityEncode(a); #define I(a, b, c) HTMLVARS #undef D #undef I // Part 4: Output the HTML form // For reals, hard code the HTML variable name and append encoded_ in front of the corresponding program variable and use %s // For ints, hard code the HTML varibale name but just use the program variable and use %d const char *NOut1 = ""; const char *NOut2 = ""; const char *wNOut1 = ""; const char *wNOut2 = ""; const char *iNOut1 = ""; const char *iNOut2 = ""; const char *bNOut1 = ""; const char *bNOut2 = ""; const char *bwNOut1 = ""; const char *bwNOut2 = ""; fprintf(index, "%s
%sBase matrix%s
%s%d%s%s·%s
", NOut1); fprintf(index, ""); fprintf(index, "", AFile); fprintf(index, "", BFile); fprintf(index, "", MemRows); fprintf(index, "", K); fprintf(index, "", IndexRange); fprintf(index, "", Indent); fprintf(index, "", Trace); fprintf(index, ""); fprintf(index, "
Test Parameters
A Matrix(filename)
B Matrix(filename)
Maximumrows/cols
Memory width (K)records
Index range
Indentcolumns
Trace Addvc0=no 1=yes
%s\n", NOut2); // Part 5: Free temporaries #define D(a, b, c) free(a); free(encoded_##a); #define I(a, b, c) HTMLVARS #undef D #undef I #undef HTMLVARS //#define GRAPHPOINTS 400 //#define GRAPHHEIGHT 200 //extern char *GifImageStoreAdd(int x, int y, int ***image, int numimage = 1); if (cmd == 0) { HTMLGraph::eDataMark DataPointMode = HTMLGraph::Square; int Color[NUMPLOTS] = { 255<<16 | 0<<8 | 0, // Air (red) 0<<16 | 255<<8 | 0, // Water (green) 0<<16 | 0<<8 | 255, // Fractal (blue) 0<<16 | 0<<8 | 0, // Pulse (black) 255<<16 | 0<<8 | 255, // DIMM (purple) 37<<16 | 40<<8 | 103, // Sandia dark blue 165<<16 | 36<<8 | 46, // Sandia dark red 0<<16 | 0<<8 | 255, // Blue 200<<16 | 255<<8 | 200, // Pale Green }; #define ROWWID 5 int Fcns[ROWWID], NewTable, EndTable, HorizSpace; struct Rowop { Opcodes op; int Fcns[ROWWID], NewTable, HorizSpace; } TmpTabrow; vector RowList; mapFcnState; for (int i = 0; i < CtlBlkSiz; i++) FcnState[ControlBlock[i].C_Op] = 0; int r = 0; int SeqVertMode = SEQVERTMODE; if (SeqVertMode) do { int HIndex; for (HIndex = 0; HIndex < ROWWID; HIndex++) TmpTabrow.Fcns[HIndex] = CtlBlkSiz; HIndex = 0; for (; r < CtlBlkSiz; r++) if (FcnState[ControlBlock[r].C_Op] == 0 && ControlBlock[r].C_Step != AY) { TmpTabrow.op = ControlBlock[r].C_Op; TmpTabrow.Fcns[HIndex++] = r; FcnState[ControlBlock[r].C_Op] = 1; if (HIndex == ROWWID) break; } if (HIndex == 0) break; TmpTabrow.NewTable = 1; TmpTabrow.HorizSpace = 1; //printf("%d: ", TmpTabrow.op); for (int i = 0; i < ROWWID; i++) printf("row[%d] = %d ", i, TmpTabrow.row[i]); printf("NewTable=%d HorizSpace=%d\n", TmpTabrow.NewTable, TmpTabrow.HorizSpace); RowList.push_back(TmpTabrow); do { HIndex = 0; for (int i = 0; i < ROWWID; i++) { int index = TmpTabrow.Fcns[i]; if (index < CtlBlkSiz && ControlBlock[TmpTabrow.Fcns[i]].C_Op == ControlBlock[TmpTabrow.Fcns[i]+1].C_Op) { TmpTabrow.Fcns[i]++; HIndex++; } else TmpTabrow.Fcns[i] = CtlBlkSiz; } if (HIndex == 0) break; TmpTabrow.NewTable = 0; //printf("%d: ", TmpTabrow.op); for (int i = 0; i < ROWWID; i++) printf("row[%d] = %d ", i, TmpTabrow.row[i]); printf("NewTable=%d HorizSpace=%d\n", TmpTabrow.NewTable, TmpTabrow.HorizSpace); RowList.push_back(TmpTabrow); } while (1); } while (r != CtlBlkSiz); r = 0; for (; r < CtlBlkSiz; r++) if (FcnState[ControlBlock[r].C_Op] == 0 && (!SeqVertMode || ControlBlock[r].C_Step == AY)) { FcnState[ControlBlock[r].C_Op] = 1; TmpTabrow.op = ControlBlock[r].C_Op; int HIndex = 0, baserow = r; TmpTabrow.NewTable = 1; TmpTabrow.HorizSpace = ControlBlock[r].C_Step == AY; for (HIndex = 0; HIndex < ROWWID; HIndex++) TmpTabrow.Fcns[HIndex] = CtlBlkSiz; HIndex = 0; do { if (HIndex == ROWWID) { //printf("%d: ", TmpTabrow.op); for (int i = 0; i < ROWWID; i++) printf("row[%d] = %d ", i, TmpTabrow.row[i]); printf("NewTable=%d HorizSpace=%d\n", TmpTabrow.NewTable, TmpTabrow.HorizSpace); RowList.push_back(TmpTabrow); TmpTabrow.NewTable = 0; for (HIndex = 0; HIndex < ROWWID; HIndex++) TmpTabrow.Fcns[HIndex] = CtlBlkSiz; HIndex = 0; } TmpTabrow.Fcns[HIndex++] = r; if (r+1 >= CtlBlkSiz || ControlBlock[baserow].C_Op != ControlBlock[r+1].C_Op) break; r++; } while (1); if (HIndex > 0) { //printf("%d: ", TmpTabrow.op); for (int i = 0; i < ROWWID; i++) printf("row[%d] = %d ", i, TmpTabrow.row[i]); printf("NewTable=%d HorizSpace=%d\n", TmpTabrow.NewTable, TmpTabrow.HorizSpace); RowList.push_back(TmpTabrow); } if (HIndex == 0) break; } while (r != CtlBlkSiz); for (int seg = 0; seg < int(RowList.size()); seg++) { for (int i = 0; i < ROWWID; i++) Fcns[i] = RowList[seg].Fcns[i]; NewTable = RowList[seg].NewTable; EndTable = seg+1 < int(RowList.size()) ? RowList[seg+1].NewTable : 1; HorizSpace = RowList[seg].HorizSpace; /*printf("%d: ", RowList[seg].op); for (int i = 0; i < ROWWID; i++) printf("%3d ", Fcns[i]); printf("TmpTabrow=%d b=%d h=%d\n", NewTable, EndTable, HorizSpace);*/ if (NewTable) { fprintf(index, "\n"); fprintf(index, ""); } int printcomment = 0; for (int line = 0; line < 4+printcomment; line++) { fprintf(index, ""); for (int cmd2 = 0; cmd2 < ROWWID; cmd2++) { int cmd = Fcns[cmd2]; if (cmd < CtlBlkSiz) switch(line) { case 0: // header line: function name fprintf(index, "\n"); break; case 1: // first line: three conditions #define CND(n, cc) ControlBlock[cmd].C_X == n ? #n : fprintf(index, "", NOut1, CNDLIST "?", NOut2); #undef CND #define CND(n, cc) ControlBlock[cmd].C_Y == n ? #n : fprintf(index, "", NOut1, CNDLIST "?", NOut2); #undef CND #define CND(n, cc) ControlBlock[cmd].C_Z == n ? #n : fprintf(index, "\n", NOut1, CNDLIST "?", NOut2); #undef CND break; case 2: // second line: action fprintf(index, "\n", NOut2); break; case 3: // third line: next function char *C; fprintf(index, "\n", NOut2); break; case 4: // fourth line: comment, if not blank if (ControlBlock[cmd].Comment != 0 && strlen(ControlBlock[cmd].Comment) > 0) fprintf(index, "", NOut1, ControlBlock[cmd].Comment, NOut2); break; } else fprintf(index, "", NOut1, NOut2); if (HorizSpace && cmd2 != ROWWID-1) fprintf(index, ""); } fprintf(index, "\n"); } if (EndTable) fprintf(index, "
", ControlBlock[cmd].Color); #define OV(s, n, t) ControlBlock[cmd].C_Op == n ? #s : fprintf(index, "%s%s%s", bwNOut1, OVLIST "?", bwNOut2); #undef OV // header line: stepping if (ControlBlock[cmd].C_Step < AY) fprintf(index, "%s.%d%s", wNOut1, ControlBlock[cmd].C_Step, wNOut2); fprintf(index, "%s%s%s%s%s%s%s%s%s%s%s", NOut1, ControlBlock[cmd].A_Fcn=='C' ? "CALL" : ControlBlock[cmd].A_Fcn=='R' ? "RET" : ControlBlock[cmd].A_Fcn=='r' ? "RET" : ControlBlock[cmd].A_Fcn=='J' ? "JMP" : "?"); // second line: side if (ControlBlock[cmd].A_Fcn!='R' && ControlBlock[cmd].A_Fcn!='r') fprintf(index, " %s.", ControlBlock[cmd].A_AB == 0 ? "A" : ControlBlock[cmd].A_AB == 1 ? "B" : ControlBlock[cmd].A_AB == 2 ? "U" : "I"); fprintf(index, "%s%s", NOut1); if (ControlBlock[cmd].A_Fcn=='C') { C = "black"; for (int j = 0; j < CtlBlkSiz; j++) if (ControlBlock[j].C_Op == ControlBlock[cmd].A_Op%100) C = ControlBlock[j].Color; #if EXPLAIN #define OV(s, n, t) ControlBlock[cmd].A_Op == n ? #s : fprintf(index, "%s [", C, OVLIST "?"); #undef OV #define OV(s, n, t) ControlBlock[cmd].A_Op == n ? #t : fprintf(index, "%s]", OVLIST "?"); #undef OV #else #define OV(s, n, t) ControlBlock[cmd].A_Op == n ? #s : fprintf(index, "%s", C, OVLIST "?"); #undef OV #endif } // third line: data path #if EXPLAIN #define VAR(s, n, t) ControlBlock[cmd].A_D == n ? #s : fprintf(index, "(%s [", VARLIST "?"); #undef VAR #define VAR(s, n, t) ControlBlock[cmd].A_D == n ? #t : fprintf(index, "%s], ", VARLIST "?"); #undef VAR #else #define VAR(s, n, t) ControlBlock[cmd].A_D == n ? #s : fprintf(index, "(%s, ", VARLIST "?"); #undef VAR #endif // third line: argument #define ARG(n, s) ControlBlock[cmd].A_Argv == n ? #n : fprintf(index, "%s)", ARGLIST "?"); #undef ARG fprintf(index, "%s%s%s%s%s %s
\n"); } #if SNCODE SN.InitSortingNetwork(K, SNWLEN, SNDEPTH, SNWLEN, SNWLEN, index); #endif S.CycleCount = 0; mysrand(123); #if MATMARKET==2 for (int rootx = 0; rootx < 12; rootx++) { // rootloop #endif int s = 0; { int capacity = 600; S.DRAM.clear(); S.DRAM.resize(capacity); for (int i = 0; i < capacity; i++) S.DRAM[i].Records.Empty(K); S.Acc.Empty(K); S.StateMachine(Cl, 0, K, qx, index); } S.CycleCount = 0; //int rootbeg = 0, rootsiz = 2; vector > GroundTruth2; GroundTruth2.resize(ROOTS); #if MATMARKET==1 { vector > A, B, C; A = ReadMatrixMarket("olm500.mtx"); B = ReadMatrixMarket("plskz362.mtx"); int m = A.size(); int acols = min(A[0].size(), B.size()); int bcols = B[0].size(); int limsz = MemRows; acols = min(acols, limsz); bcols = min(acols, limsz); m = min(m, limsz); C.resize(m); for (int i = 0; i < m; i++) C[i].resize(bcols); for (int i = 0; i < m; i++) for (int j = 0; j < acols; j++) for (int k = 0; k < bcols; k++) if (A[i][j] != 0. && B[j][k] != 0.) { Record r; int rt = myrand(); r.k.SetIndex2(k, i, bcols, m);// = i*bcols + k;//i + k*m; //r.Index ^= 0x55aa; r.Value = int(A[i][j] * B[j][k]); GroundTruth2[0][r.k] = GroundTruth2[0].find(r.k) == GroundTruth2[0].end() ? r.Value : r.Value + GroundTruth2[0][r.k]; S.Acc.AddSort(r, K); if (S.Acc.V.size() == K) { sort(S.Acc.V.begin(), S.Acc.V.end(), RecordSort1); vector A = S.Acc.V; int root = 0; S.StateMachine(Av, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(0, K, GroundTruth2), S.CycleCount/*i*/, Real); // vertical then horizontal if (Trace) S.Print("Addvc", 0, &S.Acc, Indent, Trace, K, GroundTruth2[0], qx, index); S.Acc.V.clear(); } C[i][k] += A[i][j] * B[j][k]; } if (S.Acc.V.size() > 0) { sort(S.Acc.V.begin(), S.Acc.V.end(), RecordSort1); vector A = S.Acc.V; int root = 0; S.StateMachine(Av, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(0, K, GroundTruth2), S.CycleCount/*i*/, Real); // vertical then horizontal if (Trace) S.Print("Addvc", 0, &S.Acc, Indent, Trace, K, GroundTruth2[0], qx, index); S.Acc.V.clear(); } } int repcount = 3; for (int i = 0; i < repcount; i++) { int root = 0; S.Print("Results", root, 0, Indent, Trace, K, GroundTruth2[root], qx, index); NormStrategy = i; int treesize = 0; if (i < repcount-1) { S.StateMachine(Nm, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #elif MATMARKET==0 for (int i = 0; i < MemRows; i++) { // create a new random vector that will be added to the tree #if SNCODE int limit = K;//i == 6 ? K-1 : K; vector Acc, Mem;// This is the "accumulator," used for passing variables for (int ind = 0; ind < 2; ind++) { vector &A = ind==0 ? Acc : Mem; map NoDup; #else int limit = K;//i == 6 ? K-1 : K; #endif for (int j = 0; j < limit; j++) { Record r; #if SNCODE // loop to avoid adding duplicate indices int Attempt = 0, MaxAttempts = 10000; do { int rt = myrand(); r.k.SetIndex1((rt&0x7fffffff) % IndexRange, 65536, 1); r.Value = (myrand()&0x7fffffff) % SNLOGPORTS;//10.*myrand()/MYRANDMAX; /*printf("[%d]=%f\n", r.Index, r.Value); if (r.Index == 9) double e=2.718; if (NoDup.find(r.Index) != NoDup.end()) double pi=3.12;*/ } while (++Attempt < MaxAttempts && NoDup.find(r.k.ij()) != NoDup.end()); NoDup[r.k.ij()] = 1; A.push_back(r); sort(A.begin(), A.end(), RecordSort1); #else int rt = myrand(); r.k.SetIndex1((rt&0x7fffffff) % IndexRange, 30, 30); r.Value = myrand() % 10; r.Sequence = s++; int root = 0; GroundTruth2[root][r.k] = GroundTruth2[root].find(r.k) == GroundTruth2[root].end() ? r.Value : r.Value + GroundTruth2[root][r.k]; Key kt = r.k; #if YTRANSPOSE==1 kt.Transpose(); #endif GroundTruth2[1][kt] = GroundTruth2[1].find(kt) == GroundTruth2[1].end() ? r.Value : r.Value + GroundTruth2[1][kt]; S.Acc.AddSort(r, K); #endif } #if SNCODE } sort(Acc.begin(), Acc.end(), RecordSort1); sort(Mem.begin(), Mem.end(), RecordSort1); vector Ax;// = S.Acc.Raw(); SN.RunSortNetwork(Acc, Mem, K, SNWLEN, qx, index); for (vector::iterator it = Acc.begin() ; it != Acc.end(); it++) Ax.push_back(*it); for (vector::iterator it = Mem.begin() ; it != Mem.end(); it++) Ax.push_back(*it); //Mem.clear(); sort(Ax.begin(), Ax.end(), RecordSort1); int k = 0; for (vector::iterator it = Ax.begin()+1 ; it != Ax.end(); it++) if (Ax[k].k.ij() == it->k.ij()) Ax[k].Value += it->Value; else Ax[++k] = *it; Ax.resize(k+1); int errs = 0; for (int i = 0; i < k+1; i++) { if (Ax[i].k.ij() != SN.Rval[i].k.ij() || int(Ax[i].Value) != SN.Rval[i].Value) { fprintf(index, "ERROR ERROR ERROR [%d]=%d [%d]=%f
\n", Ax[i].k.ij(), int(Ax[i].Value), SN.Rval[i].k.ij(), SN.Rval[i].Value); //printf("[%d]=%d [%d]=%f
\n", A[i].Index, int(A[i].Value), SN.Rval[i].Index, SN.Rval[i].Value); double pi=3.14; errs++; } } if (errs == 0) fprintf(index, "OK
\n"); SN.Out; //S.StateMachine(Addvc, root, K, qx, index); //(*Plotfcn)(&PlotData[0], S.Efficiency(K, GroundTruth), S.CycleCount/*i*/, Real); // vertical then horizontal //if (Trace) S.Print("Addvc", &A, Indent, Trace, K, GroundTruth, qx, index); #else Register &w = S.Acc; int root = 0; S.StateMachine(Av, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i*/, Real); // vertical then horizontal if (Trace) S.Print("Addvc", root, &w, Indent, Trace, K, GroundTruth2[root], qx, index); #endif } int repcount = 3; for (int i = 0; i < repcount; i++) { int root = 0; S.Print("Results", root, 0, Indent, Trace, K, GroundTruth2[root], qx, index); NormStrategy = i; int treesize = 0; if (i < repcount-1) { S.StateMachine(Nm, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #elif MATMARKET==2 map MatZ, MatY, MatX; int iSizYZ = 16, jSizZ = 23, jSizY = 19; /* temporarily make jSizY and jSizZ the same */ GenMatrix(0, iSizYZ, jSizZ, MatZ, Indent, Trace, GroundTruth2, s, K, qx, index); GenMatrix(1, iSizYZ, jSizY, MatY, Indent, Trace, GroundTruth2, s, K, qx, index); for (int jZ = 0; jZ < jSizZ; jZ++) for (int jY = 0; jY < jSizY; jY++) for (int iYZ = 0; iYZ < iSizYZ; iYZ++) { Key KeyZ; KeyZ.SetIndex2(iYZ, jZ); Key KeyY; KeyY.SetIndex2(iYZ, jY); Key KeyX; KeyX.SetIndex2(jZ, jY); if (MatZ.find(KeyZ) != MatZ.end()) if (MatY.find(KeyY) != MatY.end()) MatX[KeyX] += MatZ[KeyZ] * MatY[KeyY]; } const char *NMOut1 = ""; const char *NMOut2 = ""; if (MATPRT) fprintf(index, "\n", NMOut1, NMOut2); S.Acc.Empty(K); for (int iZ = 0; iZ < jSizZ; iZ++) { if (MATPRT) fprintf(index, "\n"); for (int jY = 0; jY < jSizY; jY++) { Record r; r.k.SetIndex2(iZ, jY); if (MatX.find(r.k) != MatX.end()) { r.Value = MatX[r.k]; r.Sequence = s++; GroundTruth2[2][r.k] = r.Value; } if (MATPRT) if (MatX[r.k] == 0) fprintf(index, "", NMOut1, NMOut2); else fprintf(index, "", NMOut1, MatX[r.k], NMOut2); } if (MATPRT) fprintf(index, "\n"); } if (MATPRT) fprintf(index, "
%sProduct matrix%s
%s·%s%s%d%s
\n"); #endif #if SNCODE #else const char *NOut1 = ""; const char *NOut2 = ""; #if 0 int repcount = 3; for (int i = 0; i < repcount; i++) { S.Print("Results", root, 0, Indent, Trace, K, GroundTruth2[root], qx, index); NormStrategy = i; int treesize = 0; if (i < repcount-1) { S.StateMachine(Nm, root, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #endif // normalize Z, row 0 for (int i = 0, repcount3 = 3; i < repcount3; i++) { //S.Print("Results", 0, 0, Indent, Trace, K, GroundTruth2[1], qx, index); NormStrategy = i; int treesize = 0; if (i < repcount3-1) { S.StateMachine(Nm, Z, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(0, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #if 0 // copy matrix Z, row 0, to Y, row 1 for (int i = 0; i < 1; i++) { S.Arg = Scalars(ZerKey(), -1, ZerKey(), 0); S.StateMachine(Sp, Z, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Ephemeral); // vertical then horizontal printf("Sp return to C++ %d: (%d,%d) %d (%d,%d)\n", r, S.Arg.Min().i(), S.Arg.Min().j(), S.Arg.SzGl(), S.Arg.Max().i(), S.Arg.Max().j()); r = S.Arg.Max().ij(); } #endif // normalize Y, row 1 for (int i = 0, repcount2 = 3; i < repcount2; i++) { //S.Print("Results", 1, 0, Indent, Trace, K, GroundTruth2[1], qx, index); NormStrategy = i; int treesize = 0; if (i < repcount2-1) { S.StateMachine(Nm, Y, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(1, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #if MATMARKET==2 // matrix multiply, Y, row 1 by Z, row 0 store result in X, row 2 if (1 || MMTRACE) fprintf(index, ""); for (int i = 0; i < 1; i++) { S.Arg = Scalars(ZerKey(), -1, ZerKey(), 0); S.StateMachine(Mm, Y, K, qx, index); int root = 0; (*Plotfcn)(&PlotData[0], S.Efficiency(root, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Ephemeral); // vertical then horizontal printf("Mm return to C++ %d: (%d,%d) %d (%d,%d)\n", r, S.Arg.Min().i(), S.Arg.Min().j(), S.Arg.SzGl(), S.Arg.Max().i(), S.Arg.Max().j()); r = S.Arg.Max().ij(); } if (1 || MMTRACE) fprintf(index, "
"); #if 1 // normalize X, row 2 for (int i = 0, repcount4 = 4; i < repcount4; i++) { //S.Print("Normalize X", X, 0, Indent, Trace, K, GroundTruth2[X], qx, index); //NormStrategy = i; int treesize = 0; if (i < repcount4-1) { S.StateMachine(Nm, X, K, qx, index); (*Plotfcn)(&PlotData[0], S.Efficiency(1, K, GroundTruth2), S.CycleCount/*i+MemRows*/, Real); // vertical then horizontal } } #endif #endif S.Print("Z tree (0)", Z, 0, Indent, Trace, K, GroundTruth2[Z], qx, index); S.Print("Y tree (1)", Y, 0, Indent, Trace, K, GroundTruth2[Y], qx, index); S.Print("X tree (2)", X, 0, Indent, Trace, K, GroundTruth2[X], qx, index); #endif #if SNCODE #else char buf[250]; sprintf(buf, "Memory efficiency"); int bgcolor = RGB(255, 255, 255); // note: the following graph has caused difficulties in OS X when run in a thread if (0) HTMLGraph_Print(index, buf, NUMPLOTS, 0, 1, 0, 0, &PlotData[0], Color, bgcolor, DataPointMode, // 1 for marks at the data points (NoMark or Square) HTMLGraph::SpecMinX, 0., HTMLGraph::CalcMaxX, 1., HTMLGraph::SpecMinY, 0., HTMLGraph::CalcMaxY, 1.); // Fix x axis to 0..any value if (1) for (int i = 0; i < NUMPLOTS; i++) PlotData[i].Clear(); #endif #if MATMARKET==2 } // rootloop #endif } #undef GRAPHPOINTS #undef GRAPHHEIGHT #if FANCYPAGE != 0 FancyPageEnd(index, *qx); #else fprintf(Index, "\n"); #endif qx->CloseBufferFile(); delete qx; } #undef TREENORMAL #undef TREEREVERSE