Back to home page

darwin3

 
 

    


File indexing completed on 2025-12-21 17:51:06 UTC

view on githubraw file Latest commit feb7fa5d on 2025-11-21 15:45:20 UTC
feb7fa5d1e dngo*0001 /*
                0002  * TAPENADE Automatic Differentiation Engine
                0003  * Copyright (C) 1999-2024 Inria
                0004  * See the LICENSE.md file in the project root for more information.
                0005  */
                0006 
                0007 /**** TAPENADE's ADJOINT AD STACK ****/
                0008 
                0009 // TODO:
                0010 // A few storage files (tapStackNNNNN) sometimes are not erased in the end
                0011 
                0012 
b4daa24319 Shre*0013 #include <stdlib.h>
                0014 #include <stdio.h>
                0015 #include <string.h>
feb7fa5d1e dngo*0016 #include <sys/time.h>
                0017 #include <time.h>
                0018 #include <stdint.h>
                0019 #include <inttypes.h>
b4daa24319 Shre*0020 
feb7fa5d1e dngo*0021 #include "adStack.h"
b4daa24319 Shre*0022 #include "adComplex.h"
                0023 
feb7fa5d1e dngo*0024 // This code limits the number of stack Block's kept in-core to MAX_SPACES.
                0025 // When more Block's must be kept, some Block's will be kept as files.
                0026 // File operations (storage and retrieval) are done synchronously by default,
                0027 // but they can be done asynchronously by a 2nd thread (using pthreads).
b4daa24319 Shre*0028 
feb7fa5d1e dngo*0029 // Compile with -D ADSTACK_BLOCK_SIZE=<number> to set the size in bytes of each
                0030 // stack "block" (also the size of each file used to offload stack to disk)
                0031 // See the default value below.
                0032 
                0033 // Compile with -D ADSTACK_MAX_SPACES=<number> to set the number of blocks
                0034 // allowed in main memory before offloading to disk starts.
                0035 // See the default value below.
b4daa24319 Shre*0036 
feb7fa5d1e dngo*0037 // Compile with -D ADSTACK_PREFETCH to use a 2nd thread for asynchronous file operations.
                0038 // In that case, code must be linked with -lpthread
b4daa24319 Shre*0039 
feb7fa5d1e dngo*0040 // Compile with -D ADSTACK_PROFILE to enable summary of stack usage
                0041 // through adStack_showPeakSize() and adStack_showTotalTraffic()
b4daa24319 Shre*0042 
feb7fa5d1e dngo*0043 // Compile with -D ADSTACK_TRACE to see a trace of the "file storage"
                0044 // and (optionaly) "prefetching" mechanism
                0045 
                0046 /******* Size and max number of blocks ********/
                0047 
                0048 #ifndef ADSTACK_BLOCK_SIZE
                0049 /* The default value of the size of a Block in bytes. This is also the
                0050  * size of each separate storage file, when the stack is offloaded to disk storage. */
                0051 // #define ADSTACK_BLOCK_SIZE 17 // A very small ADSTACK_BLOCK_SIZE allows for stronger testing!
                0052 // #define ADSTACK_BLOCK_SIZE 1000 // ridiculously small, just for testing.
                0053 #define ADSTACK_BLOCK_SIZE 1048576
                0054 #endif
                0055 
                0056 #ifndef ADSTACK_MAX_SPACES
                0057 /* The default value of the max number of Block's allowed in main memory.
                0058  * If more Block's are needed,the older Block's will be offloaded to disk (and retrieved later). */
                0059 #define ADSTACK_MAX_SPACES 8000
                0060 #endif
                0061 
                0062 /**************** Data structures and globals ******************/
                0063 
                0064 #ifdef ADSTACK_PREFETCH
                0065 
                0066 #include <pthread.h>
                0067 
                0068 /* Asynchronous lookahead: number of Block's that we may enqueue for
                0069  * anticipated "preStore" or "preRestore" (before or after) current Block.
                0070  * We assume/require that 2*FETCHAHEAD < ADSTACK_MAX_SPACES, to
                0071  * avoid (possible?) conflicts between preStoring and preRestoring. */
                0072 #define FETCHAHEAD 10
                0073 
                0074 pthread_t fileStorageThread ;
                0075 pthread_mutex_t fileStorageMutex;
                0076 pthread_cond_t enqueuedStorageCV, doneStoreOrRestoreCV ;
                0077 
                0078 #endif
                0079 
                0080 #ifdef ADSTACK_TRACE
                0081 // When not set to -1, DEBUG mode will show only actions about the space with this "id" field.
                0082 static int tracedId = -1 ;
                0083 #endif
b4daa24319 Shre*0084 
feb7fa5d1e dngo*0085 typedef enum {INUSE, STORED} CONTENTS_STATE ;
                0086 typedef enum {NOACTION, STORE, RESTORE} ACTION ;
                0087 
                0088 char* stateNames[] = {"U", "S"};
                0089 
                0090 /** One elementary (large) chunk of memory used by the stack.
                0091  * It is also the atomic chunk of memory that may be stored in each file */
                0092 typedef struct {
                0093   unsigned int rank ;         // From 1 up, or 0 for "not used yet"
                0094   CONTENTS_STATE state ;      // One of {INUSE, STORED}
                0095   char contents[ADSTACK_BLOCK_SIZE] ; // The main storage space.
                0096 #ifdef ADSTACK_TRACE
                0097   int id ; //Only to have a distinct name (char 'a'+id) for debug!
                0098 #endif
                0099 } BlockContents ;
                0100 
                0101 /** The stack is a fwd-bwd-chained list of DoubleChainedBlock objects.
                0102  * Each DoubleChainedBlock holds a pointer to the BlockContents that
                0103  * actually holds the memory space used. */
b4daa24319 Shre*0104 typedef struct _DoubleChainedBlock{
feb7fa5d1e dngo*0105   unsigned int rank ;  // From 1 up
b4daa24319 Shre*0106   struct _DoubleChainedBlock *prev ;
                0107   struct _DoubleChainedBlock *next ;
feb7fa5d1e dngo*0108   BlockContents* toContents ;
b4daa24319 Shre*0109 } DoubleChainedBlock ;
                0110 
feb7fa5d1e dngo*0111 /** Used to build the name of each stack storage file.
                0112  * Used only by 2nd thread */
                0113 char tapStackFileName[14] ;
                0114 
                0115 /** Memorizes the file action currently being done (asynchronously).
                0116  * These 3 globals are written only by 2nd thread, only in a locked section,
                0117  * and they may be read by 1st thread, only in a locked section. */
                0118 ACTION fileActionBeingDone = NOACTION ;
                0119 BlockContents *spaceBeingDone = NULL ;
                0120 int rankBeingDone = -1 ;
                0121 
                0122 // We call "current location" the pair of
                0123 // (DoubleChainedBlock *) curStack // the current top stack block.
                0124 // (int) tappos                    // the offset of the current top in the current top stack block.
                0125 
                0126 /** A block and an integer to keep the current top in the block. When the block
                0127  * is full, a fresh block is added on top of the stack and will receive the
                0128  * new pushes. During popping, when a block becomes empty, the block below
                0129  * becomes current, with the current top at its topmost position.
                0130  * These 3 globals are used only by 1st thread */
                0131 static DoubleChainedBlock *curStack = NULL ;
                0132 static char* tapblock = NULL ;
                0133 static int tappos  = ADSTACK_BLOCK_SIZE ;
                0134 
                0135 /** All the BlockContents allocated. We allow only ADSTACK_MAX_SPACES of them.
                0136  * Used only by 1st thread */
                0137 static BlockContents* allBlockContents[ADSTACK_MAX_SPACES] ; //assume they are all initialized to NULL
                0138 
                0139 /** Structure keeping the needed info for one repetition level (used to read from
                0140  * the stack without removing the values read, thus allowing for reading again).
                0141  * As we can have nested repetition levels, these structures can be stacked. */
b4daa24319 Shre*0142 typedef struct _RepetitionLevel {
                0143   int active ;
feb7fa5d1e dngo*0144   // The top location (block+offset) of the re-readable part:
b4daa24319 Shre*0145   DoubleChainedBlock* resumePointBlock ;
                0146   int resumePoint ;
feb7fa5d1e dngo*0147   // The "freePush" location where one can push/pop (if needed) without overwriting the re-readable values:
b4daa24319 Shre*0148   DoubleChainedBlock* freePushBlock ;
                0149   int freePush ;
feb7fa5d1e dngo*0150   // The saved location where one must pop back when returning from the "freePush" location:
                0151   DoubleChainedBlock* backPopBlock ;
                0152   int hasBackPop ;
                0153   int backPop ;
b4daa24319 Shre*0154   unsigned int storedadbitbuf ;
                0155   int storedadbitibuf ;
                0156   struct _RepetitionLevel *previous ;
                0157 } RepetitionLevel ;
                0158 
feb7fa5d1e dngo*0159 /** The current stack of repetition levels. Initially empty
                0160  * Used only by 1st thread */
b4daa24319 Shre*0161 RepetitionLevel *topRepetitionPoint = NULL ;
                0162 
feb7fa5d1e dngo*0163 /** Pushing single bits is different from the rest: we collect
                0164  * 32 bits in the integer below, before pushing that to the stack.
                0165  * Used only by 1st thread */
b4daa24319 Shre*0166 static unsigned int adbitbuf = 0 ;
                0167 static int adbitibuf = 0 ;
                0168 
                0169 /** Accumulates the number of bytes pushed and popped */
feb7fa5d1e dngo*0170 static u_int64_t pushPopTraffic = 0 ;
b4daa24319 Shre*0171 
                0172 /** Remembers the maximum number of stack Blocks used */
feb7fa5d1e dngo*0173 static u_int64_t maxBlocks = 0 ;
b4daa24319 Shre*0174 
                0175 /* All data structures must be threadprivate, so that each OpenMP thread has
                0176    its own stack. If the stack is compiled with OpenMP support and then used
                0177    in a program with no OpenMP parallel regions, the stack will work as
                0178    expected without using any extra resources. */
                0179 #pragma omp threadprivate(tappos, tapblock, curStack, adbitbuf, adbitibuf, topRepetitionPoint)
                0180 
feb7fa5d1e dngo*0181 // pre-declare a few prototypes.
                0182 void showLocation(DoubleChainedBlock *locBlock, int loc) ;
                0183 void dumpContents(BlockContents *space) ;
                0184 void dumpStack(DoubleChainedBlock *st) ;
                0185 void dumpRepetitionLevels() ;
b4daa24319 Shre*0186 
feb7fa5d1e dngo*0187 char* pushBlock() ;
                0188 char* popBlock() ;
                0189 void removeStorageFile(int blockRank) ;
                0190 void storeInFile(BlockContents* blockContents) ;
                0191 void restoreFromFile(BlockContents* blockContents) ;
b4daa24319 Shre*0192 
feb7fa5d1e dngo*0193 #ifdef ADSTACK_PREFETCH
b4daa24319 Shre*0194 
feb7fa5d1e dngo*0195 /**** Queue of requested file store/restore actions (only when asynchronous) ****/
                0196 
                0197 void dumpFileActionQueue() ;
                0198 #endif
                0199 
                0200 /** One cell of the queue of requested file store/restore actions */
                0201 typedef struct _FileActionCell {
                0202   struct _FileActionCell *next ;
                0203   int restoredRank ;
                0204   ACTION action ; // One of {STORE, RESTORE}
                0205   BlockContents *space ;
                0206 } FileActionCell ;
                0207 
                0208 /** Globals that keep the head and tail of the queue of requested file store/restore actions */
                0209 FileActionCell *fileActionQueueHead = NULL;
                0210 FileActionCell *fileActionQueueTail = NULL;
                0211 
                0212 #ifdef ADSTACK_PREFETCH
                0213 /** Used only by 1st thread. Always called inside pthread_mutex_lock(&fileStorageMutex) */
                0214 int enqueued(BlockContents *space) {
                0215   int found = 0 ;
                0216   FileActionCell *curCell = fileActionQueueHead ;
                0217   while (!found && curCell) {
                0218     found = (curCell->space==space) ;
                0219     curCell = curCell->next ;
                0220   }
                0221   return found ;
                0222 }
                0223 
                0224 /** Used only by 1st thread, always inside pthread_mutex_lock(&fileStorageMutex) */
                0225 void addTailFileAction(BlockContents *space, ACTION action, int restoredRank) {
                0226   FileActionCell *newCell = (FileActionCell*)malloc(sizeof(FileActionCell)) ;
                0227   newCell->next = NULL ;
                0228   newCell->action = action ;
                0229   newCell->restoredRank = restoredRank ;
                0230   newCell->space = space ;
                0231   if (fileActionQueueHead==NULL) {
                0232     fileActionQueueHead = newCell ;
                0233     fileActionQueueTail = newCell ;
                0234   } else {
                0235     fileActionQueueTail->next = newCell ;
                0236     fileActionQueueTail = newCell ;
                0237   }
                0238 }
                0239 
                0240 /** Used only by 2nd thread, always inside pthread_mutex_lock(&fileStorageMutex) */
                0241 BlockContents *popHeadFileAction() {
                0242   BlockContents *result = fileActionQueueHead->space ;
                0243   if (fileActionQueueHead==fileActionQueueTail) {
                0244     free(fileActionQueueHead) ;
                0245     fileActionQueueHead = NULL ;
                0246     fileActionQueueTail = NULL ;
                0247   } else {
                0248     FileActionCell *tofree = fileActionQueueHead ;
                0249     fileActionQueueHead = tofree->next ;
                0250     free(tofree) ;
                0251   }
                0252   return result ;
                0253 }
                0254 
                0255 /** Used only by 1st thread. Always called inside pthread_mutex_lock(&fileStorageMutex) */
                0256 void dequeueFileAction(FileActionCell *cell) {
                0257   FileActionCell **toheadcell = &(fileActionQueueHead) ;
                0258   FileActionCell *lastCellSeen = NULL ;
                0259   while (*toheadcell) {
                0260     if (*toheadcell==cell) {
                0261       *toheadcell = cell->next ;
                0262       free(cell) ;
                0263       if (!*toheadcell) { // We removed the last in queue
                0264         fileActionQueueTail = lastCellSeen ;
                0265       }
                0266     } else {
                0267       lastCellSeen = *toheadcell ;
                0268       toheadcell = &((*toheadcell)->next) ;
                0269     }
                0270   }
                0271 }
                0272 
                0273 /** Used only by 1st thread. Always called inside pthread_mutex_lock(&fileStorageMutex) */
                0274 void emptyFileActionQueue() {
                0275   while (fileActionQueueHead) {
                0276     FileActionCell *tofree = fileActionQueueHead ;
                0277 #ifdef ADSTACK_TRACE
                0278     printf(" Forget %s (%c: %02i %s)\n",
                0279            (tofree->action==STORE ? "store" : "restore"),
                0280            'a'+tofree->space->id,
                0281            tofree->space->rank,
                0282            stateNames[tofree->space->state]) ;
                0283 #endif
                0284     fileActionQueueHead = tofree->next ;
                0285     free(tofree) ;
                0286   }
                0287   fileActionQueueTail = NULL ;
                0288 }
                0289 
                0290 /** Used only by 1st thread. Always called inside pthread_mutex_lock(&fileStorageMutex) */
                0291 FileActionCell *alreadyEnqueuedRestore(BlockContents *space) {
                0292   FileActionCell *found = NULL ;
                0293   FileActionCell *curCell = fileActionQueueHead ;
                0294   while (!found && curCell) {
                0295     if (curCell->action==RESTORE
                0296         && curCell->space==space) {
                0297       found = curCell ;
                0298     }
                0299     curCell = curCell->next ;
                0300   }
                0301   return found ;
                0302 }
                0303 
                0304 /************ Prefetching mechanism (only when asynchronous) *************/
                0305 
                0306 /** True when the last move was a pushBlock (or equivalent).
                0307  * Used only by 1st thread */
                0308 static int goingForward = 1 ;
                0309 
                0310 /** Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0311 void enqueueFileAction(BlockContents* space, ACTION action, int restoredRank) {
                0312   struct timespec ts ;
                0313 #ifdef ADSTACK_TRACE
                0314   if (tracedId==-1 || tracedId==space->id) {
                0315     clock_gettime(CLOCK_REALTIME, &ts);
                0316     if (action==STORE) {
                0317       printf("t%09i Enqueue store (%c: %02i %s)\n", ts.tv_nsec,
                0318            'a'+space->id,
                0319            space->rank,
                0320            stateNames[space->state]) ;
                0321     } else if (action==RESTORE) {
                0322       printf("t%09i Enqueue restore %02i into (%c: %02i %s)\n", ts.tv_nsec,
                0323            restoredRank,
                0324            'a'+space->id,
                0325            space->rank,
                0326            stateNames[space->state]) ;
                0327     }
                0328   }
                0329 #endif
                0330   addTailFileAction(space, action, restoredRank) ;
                0331 #ifdef ADSTACK_TRACE
                0332   clock_gettime(CLOCK_REALTIME, &ts);
                0333   printf("t%09i Send signal enqueuedStorageCV\n", ts.tv_nsec) ;
                0334 #endif
                0335   pthread_cond_signal(&enqueuedStorageCV) ;  
                0336 }
                0337 
                0338 /** Register a request for storing the given BlockContents to file.
                0339  * Rationale: IF the queue already contains a store request for this BlockContents,
                0340  *  or if the fileActionBeingDone is precisely that, THEN (we assume that this other
                0341  *  store deals with the same rank as the given storedRank in this BlockContents and)
                0342  *  we don't enqueue this request because it is already requested or being done.
                0343  *  ELSE IF the queue already contains a restore request for this BlockContents
                0344  *  or if the fileActionBeingDone is precisely that, THEN (we assume that this restore
                0345  *  has already been preceded by the appropriate store, and anyway it is too late for
                0346  *  storing, and) we don't enqueue this request because it is obsolete.
                0347  *  ELSE the queue contains nothing about this BlockContents and the fileActionBeingDone,
                0348  *  if any, does not concern this BlockContents, and therefore we enqueue the given request.
                0349  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0350 void preStoreBlock(BlockContents *future, int storedRank) {
                0351 #ifdef ADSTACK_TRACE
                0352   if (tracedId==-1 || tracedId==future->id) {
                0353     struct timespec ts ;
                0354     clock_gettime(CLOCK_REALTIME, &ts);
                0355     printf("t%09i preStoreBlock (%c: %02i %s)\n", ts.tv_nsec,
                0356            'a'+future->id, future->rank, stateNames[future->state]) ;
                0357     dumpRepetitionLevels() ;
                0358   }
                0359 #endif
                0360   // Don't enqueue for store if already stored:
                0361   if (future->state==INUSE) {
                0362     if (spaceBeingDone==future || enqueued(future)) {
                0363       // possibly check that ranks match, but a priori don't enqueue
                0364     } else {
                0365       enqueueFileAction(future, STORE, storedRank) ;
                0366     }
                0367   }
                0368 }
                0369 
                0370 /** Register a request for restoring values for the given restoredRank,
                0371  * from file, into the given BlockContents.
                0372  * Rationale: IF the fileActionBeingDone is precisely a restore for this BlockContents,
                0373  *  THEN (either the restored rank is the same and we don't enqueue the request
                0374  *  because it is being done anyway, or it is for another rank and then we must
                0375  *  enqueue the given request),
                0376  *  ELSE IF the queue already contains a restore request for this BlockContents,
                0377  *  THEN we believe this already enqueued restore request is obsolete, and we
                0378  *  just replace in-place its enqueued rank with the given restoredRank,
                0379  *  ELSE IF the queue already contains (just) a store request for this BlockContents,
                0380  *  or if the fileActionBeingDone is precisely that, THEN we enqueue the given request,
                0381  *  ELSE the queue contains nothing about this BlockContents and the fileActionBeingDone,
                0382  *  if any, does not concern this BlockContents, and therefore we must first enqueue
                0383  *  a request to store the present BlockContents (because restoring will overwrite it)
                0384  *  if not already stored yet, and then enqueue the given request.
                0385  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0386 void preRestoreBlock(BlockContents *future, int restoredRank) {
                0387 #ifdef ADSTACK_TRACE
                0388   if (tracedId==-1 || tracedId==future->id) {
                0389     struct timespec ts;
                0390     clock_gettime(CLOCK_REALTIME, &ts);
                0391     printf("t%09i preRestoreBlock %02i INTO (%c: %02i %s)\n", ts.tv_nsec,
                0392            restoredRank, 'a'+future->id, future->rank, stateNames[future->state]) ;
                0393     dumpRepetitionLevels() ;
                0394   }
                0395 #endif
                0396   FileActionCell *enqueuedRestore ;
                0397   if (fileActionBeingDone==RESTORE && spaceBeingDone==future) {
                0398     if (rankBeingDone!=restoredRank) {
                0399       enqueueFileAction(future, RESTORE, restoredRank) ;
                0400     }
                0401   } else if ((enqueuedRestore = alreadyEnqueuedRestore(future)) != NULL) {
                0402     enqueuedRestore->restoredRank = restoredRank ;
                0403     if (future->rank==restoredRank) {
                0404       dequeueFileAction(enqueuedRestore) ;
                0405     }
                0406   } else if ((fileActionBeingDone==STORE && spaceBeingDone==future)
                0407              || enqueued(future)) {
                0408     if (future->rank!=restoredRank) {
                0409       enqueueFileAction(future, RESTORE, restoredRank) ;
                0410     }
                0411   } else {
                0412     if (future->rank!=restoredRank) {
                0413       if (future->state==INUSE) {
                0414         enqueueFileAction(future, STORE, 0) ;
                0415       }
                0416       enqueueFileAction(future, RESTORE, restoredRank) ;
                0417     }
                0418   }
                0419 }
                0420 
                0421 /** Enqueue the anticipated action for the current Block and FETCHAHEAD Blocks after it.
                0422  * When not already done, this action is a store of whatever contents may be in the Block,
                0423  * because this method is called when PUSHing, and this contents will be overwritten by the coming PUSHes.
                0424  * Used only by 1st thread, Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0425 void preStore() {
                0426   if (!goingForward) {
                0427     emptyFileActionQueue() ;
                0428     goingForward = 1 ;
                0429   }
                0430   preStoreBlock(curStack->toContents, curStack->rank) ;
                0431   int curIndex = (curStack->rank - 1)%ADSTACK_MAX_SPACES ;
                0432   for (int i=1 ; i<=FETCHAHEAD ; ++i) {
                0433     BlockContents *future = allBlockContents[(curIndex+i<ADSTACK_MAX_SPACES ? curIndex+i : curIndex+i-ADSTACK_MAX_SPACES)] ;
                0434     if (future) {
                0435       preStoreBlock(future, curStack->rank + i) ;
                0436     }
                0437   }
                0438 }
                0439 
                0440 /** Special case of preStore(): the current stack top is the freePush location of the current repetition level.
                0441  * This implies that the contents of this top Block already have some stored values, that must be restored.
                0442  * The anticipated action for the Blocks after current is a pre-store, like in the general case.
                0443  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0444 void preStoreAtFreePush() {
                0445   if (!goingForward) {
                0446     emptyFileActionQueue() ;
                0447     goingForward = 1 ;
                0448   }
                0449   // curStack just jumped to the freePush block. Therefore
                0450   // we must retrieve its contents to preserve the part of
                0451   // its contents which is *before* the freePush location.
                0452   preRestoreBlock(curStack->toContents, curStack->rank) ;  
                0453   int curIndex = (curStack->rank - 1)%ADSTACK_MAX_SPACES ;
                0454   for (int i=1 ; i<=FETCHAHEAD ; ++i) {
                0455     BlockContents *future = allBlockContents[(curIndex+i<ADSTACK_MAX_SPACES ? curIndex+i : curIndex+i-ADSTACK_MAX_SPACES)] ;
                0456     if (future) {
                0457       preStoreBlock(future, curStack->rank + i) ;
                0458     }
                0459   }
                0460 }
                0461 
                0462 /** Enqueue the anticipated action for the current Block and FETCHAHEAD Blocks before it.
                0463  * When not already done, this action is a restore because this method is called when POPping.
                0464  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0465 void preRestore() {
                0466   if (goingForward) {
                0467     emptyFileActionQueue() ;
                0468     goingForward = 0 ;
                0469   }
                0470   preRestoreBlock(curStack->toContents, curStack->rank) ;
                0471   int curIndex = (curStack->rank - 1)%ADSTACK_MAX_SPACES ;
                0472   for (int i=0 ; i<=FETCHAHEAD && i<curStack->rank ; ++i) {
                0473     BlockContents *future = allBlockContents[(curIndex-i>=0 ? curIndex-i : curIndex-i+ADSTACK_MAX_SPACES)] ;
                0474     preRestoreBlock(future, curStack->rank - i) ;
                0475   }
                0476 }
b4daa24319 Shre*0477 
feb7fa5d1e dngo*0478 /** Wait until the contents of current stack top can be overwritten (i.e. forward),
                0479  * i.e. are used but already STORED in a file (which also applies to the special initial case with rank==0)
                0480  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0481 void waitForward() {
                0482   BlockContents *space = curStack->toContents ;
                0483   // We must wait as long as this space's state is INUSE, or also if this space
                0484   // is being read/written asynchronously or is enqueued for future read/write:
                0485   struct timespec ts;
                0486   while (spaceBeingDone==space
                0487          || space->state==INUSE
                0488          || enqueued(space)) {
                0489 #ifdef ADSTACK_TRACE
                0490       clock_gettime(CLOCK_REALTIME, &ts);
                0491       printf("t%09i Waiting forward for [%02i (%c: %02i %s)] %c%c%c\n", ts.tv_nsec,
                0492              curStack->rank, 'a'+space->id, space->rank, stateNames[space->state],
                0493              (spaceBeingDone==space ? 't' : 'f'),
                0494              (space->state==INUSE ? 't' : 'f'),
                0495              (enqueued(space) ? 't' : 'f')) ;
                0496 #endif
                0497       int rt = 0 ;
                0498 //    clock_gettime(CLOCK_REALTIME, &ts);
                0499 //    ts.tv_sec += 1;
                0500 //    rt = pthread_cond_timedwait(&doneStoreOrRestoreCV, &fileStorageMutex, &ts) ;
                0501       pthread_cond_wait(&doneStoreOrRestoreCV, &fileStorageMutex) ;
                0502 #ifdef ADSTACK_TRACE
                0503       clock_gettime(CLOCK_REALTIME, &ts);
                0504       printf("t%09i Wait forward %s\n", ts.tv_nsec, (rt ? "timed out" : "woke up")) ;
                0505 #endif
                0506   }
                0507 #ifdef ADSTACK_TRACE
                0508   clock_gettime(CLOCK_REALTIME, &ts);
                0509   printf("t%09i Done waiting forward [%02i (%c: %02i %s)]\n", ts.tv_nsec,
                0510          curStack->rank, 'a'+space->id, space->rank, stateNames[space->state]) ;
                0511 #endif
                0512 }
                0513 
                0514 /** Wait until the contents of current stack top can be popped (i.e. read backwards).
                0515  * i.e. do contain the data about the current stack top.
                0516  * Used only by 1st thread. Must be called inside pthread_mutex_lock(&fileStorageMutex) */
                0517 void waitBackward() {
                0518   BlockContents *space = curStack->toContents ;
                0519   struct timespec ts;
                0520   // We must wait as long as the rank stored in this space is not
                0521   // the one required at this location of the stack, or also if this space
                0522   // is being read/written asynchronously or is enqueued for future read/write:
                0523   while (spaceBeingDone==space
                0524          || space->rank!=curStack->rank
                0525          || enqueued(space)) {
                0526 #ifdef ADSTACK_TRACE
                0527       clock_gettime(CLOCK_REALTIME, &ts);
                0528       printf("t%09i Waiting backward for %02i (%c: %02i %s) %c%c%c\n", ts.tv_nsec,
                0529              curStack->rank, 'a'+space->id, space->rank, stateNames[space->state],
                0530              (spaceBeingDone==space ? 't' : 'f'),
                0531              (space->rank!=curStack->rank ? 't' : 'f'),
                0532              (enqueued(space) ? 't' : 'f')) ;
                0533 #endif
                0534       int rt = 0 ;
                0535 //    struct timespec ts;
                0536 //    clock_gettime(CLOCK_REALTIME, &ts);
                0537 //    ts.tv_sec += 1;
                0538 //    rt = pthread_cond_timedwait(&doneStoreOrRestoreCV, &fileStorageMutex, &ts) ;
                0539       pthread_cond_wait(&doneStoreOrRestoreCV, &fileStorageMutex) ;
                0540 #ifdef ADSTACK_TRACE
                0541       clock_gettime(CLOCK_REALTIME, &ts);
                0542       printf("t%09i Wait backward %s for %02i (%c: %02i %s)\n", ts.tv_nsec,
                0543              (rt ? "timed out" : "woke up"),
                0544              curStack->rank, 'a'+space->id, space->rank, stateNames[space->state]) ;
                0545 #endif
                0546   }
                0547 #ifdef ADSTACK_TRACE
                0548   clock_gettime(CLOCK_REALTIME, &ts);
                0549   printf("t%09i Done waiting backward [%02i (%c: %02i %s)]\n", ts.tv_nsec,
                0550          curStack->rank, 'a'+space->id, space->rank, stateNames[space->state]) ;
                0551 #endif    
                0552 }
                0553 
                0554 #else
                0555 
                0556 /********* Code when no prefetching and no queue or requested file actions *********/
                0557 
                0558 int enqueued(BlockContents *space) {return 0 ;}
                0559 
                0560 void checkForward() {
                0561   // Synchronous mode. Just make sure we can overwrite in this space:
                0562   BlockContents *space = curStack->toContents ;
                0563   if (space->state==INUSE) {
                0564 #ifdef ADSTACK_TRACE
                0565       if (tracedId==-1 || tracedId==space->id) {
                0566         printf(" store (%c: %02i %s) into file tapStack%05i\n", 'a'+space->id,
                0567                space->rank, stateNames[space->state], space->rank) ;
                0568       }
                0569 #endif
                0570       storeInFile(space) ;
                0571       space->state = STORED ;
                0572   }
                0573 }
                0574 
                0575 void checkBackward() {
                0576   // Synchronous mode, Just make sure this space contains the values that we will need:
                0577   BlockContents *space = curStack->toContents ;
                0578   if (space->rank!=curStack->rank) {
                0579       if (space->state==INUSE) {
                0580 #ifdef ADSTACK_TRACE
                0581         if (tracedId==-1 || tracedId==space->id) {
                0582           printf(" store (%c: %02i %s) into file tapStack%05i\n", 'a'+space->id,
                0583                  space->rank, stateNames[space->state], space->rank) ;
                0584         }
                0585 #endif
                0586         storeInFile(space) ;
                0587       }
                0588       space->rank = curStack->rank ;
                0589 #ifdef ADSTACK_TRACE
                0590       if (tracedId==-1 || tracedId==space->id) {
                0591         printf(" restore (%c: %02i %s) from file tapStack%05i\n", 'a'+space->id,
                0592                space->rank, stateNames[space->state], space->rank) ;
                0593       }
                0594 #endif
                0595       restoreFromFile(space) ;
                0596       space->state = STORED ;
                0597   }
                0598 }
                0599 
                0600 #endif
                0601   
                0602 /***************** Repeated access mechanism *************/
                0603 
                0604 /** Used only by 1st thread. Not locked */
b4daa24319 Shre*0605 void setBackPopToCurrentLocation(RepetitionLevel *repetitionLevel) {
                0606   repetitionLevel->hasBackPop = 1 ;
                0607   repetitionLevel->backPopBlock = curStack ;
                0608   repetitionLevel->backPop = tappos ;
                0609 }
                0610 
feb7fa5d1e dngo*0611 /** Used only by 1st thread. Not locked, but contains a locked section. */
b4daa24319 Shre*0612 void setCurrentLocationToBackPop(RepetitionLevel *repetitionLevel) {
                0613   curStack = repetitionLevel->backPopBlock ;
feb7fa5d1e dngo*0614 #ifdef ADSTACK_PREFETCH
                0615   // Start a locked section on 1st thread:
                0616   pthread_mutex_lock(&fileStorageMutex) ;
                0617   emptyFileActionQueue() ;
                0618   goingForward = 0 ;
                0619   preRestore() ;
                0620   waitBackward() ;
                0621   curStack->toContents->rank = curStack->rank ;
                0622   pthread_mutex_unlock(&fileStorageMutex) ;
                0623   // End locked section on 1st thread.
                0624 #else
                0625   checkBackward() ;
                0626   curStack->toContents->rank = curStack->rank ;
                0627 #endif
                0628 #ifdef ADSTACK_TRACE
                0629   struct timespec ts;
                0630   clock_gettime(CLOCK_REALTIME, &ts);
                0631   printf("t%09i %02i <= BackPop\n", ts.tv_nsec, curStack->rank) ;
                0632 #endif
                0633   tapblock = curStack->toContents->contents ;
b4daa24319 Shre*0634   tappos = repetitionLevel->backPop ;
                0635 }
                0636 
feb7fa5d1e dngo*0637 /** Used only by 1st thread. Not locked */
b4daa24319 Shre*0638 void setResumePointToCurrentLocation(RepetitionLevel *repetitionLevel) {
                0639   repetitionLevel->resumePointBlock = curStack ;
                0640   repetitionLevel->resumePoint = tappos ;
                0641 }
                0642 
feb7fa5d1e dngo*0643 /** Used only by 1st thread. Not locked, but contains a locked section. */
b4daa24319 Shre*0644 void setCurrentLocationToResumePoint(RepetitionLevel *repetitionLevel) {
                0645   curStack = repetitionLevel->resumePointBlock ;
feb7fa5d1e dngo*0646 #ifdef ADSTACK_PREFETCH
                0647   // Start a locked section on 1st thread:
                0648   pthread_mutex_lock(&fileStorageMutex) ;
                0649   emptyFileActionQueue() ;
                0650   goingForward = 0 ;
                0651   preRestore() ;
                0652   waitBackward() ;
                0653   curStack->toContents->rank = curStack->rank ;
                0654   pthread_mutex_unlock(&fileStorageMutex) ;
                0655   // End locked section on 1st thread.
                0656 #else
                0657   checkBackward() ;
                0658   curStack->toContents->rank = curStack->rank ;
                0659 #endif
                0660 #ifdef ADSTACK_TRACE
                0661   struct timespec ts;
                0662   clock_gettime(CLOCK_REALTIME, &ts);
                0663   printf("t%09i %02i <= Repeat\n", ts.tv_nsec, curStack->rank) ;
                0664 #endif
                0665   tapblock = curStack->toContents->contents ;
b4daa24319 Shre*0666   tappos = repetitionLevel->resumePoint ;
                0667 } 
                0668 
feb7fa5d1e dngo*0669 /** Used only by 1st thread. Not locked */
b4daa24319 Shre*0670 void setFreePushToCurrentLocation(RepetitionLevel *repetitionLevel) {
                0671   repetitionLevel->freePushBlock = curStack ;
                0672   repetitionLevel->freePush = tappos ;
                0673 }
                0674 
feb7fa5d1e dngo*0675 /** Used only by 1st thread. Not locked, but contains a locked section. */
b4daa24319 Shre*0676 void setCurrentLocationToFreePush(RepetitionLevel *repetitionLevel) {
                0677   curStack = repetitionLevel->freePushBlock ;
feb7fa5d1e dngo*0678 #ifdef ADSTACK_PREFETCH
                0679   // Start a locked section on 1st thread:
                0680   pthread_mutex_lock(&fileStorageMutex) ;
                0681   emptyFileActionQueue() ;
                0682   goingForward = 1 ;
                0683   preStoreAtFreePush() ;
                0684   waitBackward() ;
                0685   curStack->toContents->rank = curStack->rank ;
                0686   curStack->toContents->state = INUSE ; // because we are going to push into curStack
                0687   pthread_mutex_unlock(&fileStorageMutex) ;
                0688   // End locked section on 1st thread.
                0689 #else
                0690   checkBackward() ;
                0691   curStack->toContents->rank = curStack->rank ;
                0692   curStack->toContents->state = INUSE ; // because we are going to push into curStack
                0693 #endif
                0694 #ifdef ADSTACK_TRACE
                0695   struct timespec ts;
                0696   clock_gettime(CLOCK_REALTIME, &ts);
                0697   printf("t%09i FreePush => %02i\n", ts.tv_nsec, curStack->rank) ;
                0698 #endif
                0699   tapblock = curStack->toContents->contents ;
b4daa24319 Shre*0700   tappos = repetitionLevel->freePush ;
                0701 } 
                0702 
                0703 //TODO: try inline this function for efficiency:
feb7fa5d1e dngo*0704 /** Used only by 1st thread. Not locked */
b4daa24319 Shre*0705 int currentLocationStrictBelowFreePush(RepetitionLevel *repetitionLevel) {
feb7fa5d1e dngo*0706   // Not as simple as it could be, because N;ADSTACK_BLOCK_SIZE <=> N+1;0
                0707   //  and both may happen due to initial NULL curStack...
                0708   int curL1 = curStack->rank ;
                0709   int curL2 = tappos ;
                0710   int fpL1 = repetitionLevel->freePushBlock->rank ;
                0711   int fpL2 = repetitionLevel->freePush ;
                0712   if (curL2==ADSTACK_BLOCK_SIZE) {++curL1 ; curL2=0 ;}
                0713   if (fpL2==ADSTACK_BLOCK_SIZE) {++fpL1 ; fpL2=0 ;}
                0714   return (curL1<fpL1 || (curL1==fpL1 && curL2<fpL2)) ;
b4daa24319 Shre*0715 }
                0716 
                0717 //TODO: try inline this function for efficiency:
feb7fa5d1e dngo*0718 /** Used only by 1st thread. Not locked */
b4daa24319 Shre*0719 int currentLocationEqualsFreePush(RepetitionLevel *repetitionLevel) {
feb7fa5d1e dngo*0720   // Not as simple as it could be, because N;ADSTACK_BLOCK_SIZE <=> N+1;0
                0721   // and both may happen due to initial NULL curStack...
                0722   int curL1 = curStack->rank ;
                0723   int curL2 = tappos ;
                0724   int fpL1 = repetitionLevel->freePushBlock->rank ;
                0725   int fpL2 = repetitionLevel->freePush ;
                0726   if (curL2==ADSTACK_BLOCK_SIZE) {++curL1 ; curL2=0 ;}
                0727   if (fpL2==ADSTACK_BLOCK_SIZE) {++fpL1 ; fpL2=0 ;}
                0728   return (curL1==fpL1 && curL2==fpL2) ;
b4daa24319 Shre*0729 }
                0730 
feb7fa5d1e dngo*0731 //TODO: try inline this function for efficiency:
                0732 /** Used only by 1st thread. Not locked */
                0733 int currentLocationEqualsBackPop(RepetitionLevel *repetitionLevel) {
                0734   // Not as simple as it could be, because N;ADSTACK_BLOCK_SIZE <=> N+1;0
                0735   // and both may happen due to initial NULL curStack...
                0736   int curL1 = curStack->rank ;
                0737   int curL2 = tappos ;
                0738   int bpL1 = repetitionLevel->backPopBlock->rank ;
                0739   int bpL2 = repetitionLevel->backPop ;
                0740   if (curL2==ADSTACK_BLOCK_SIZE) {++curL1 ; curL2=0 ;}
                0741   if (bpL2==ADSTACK_BLOCK_SIZE) {++bpL1 ; bpL2=0 ;}
                0742   return (curL1==bpL1 && curL2==bpL2) ;
b4daa24319 Shre*0743 }
                0744 
                0745 /** If we are in a protected, read-only section,
feb7fa5d1e dngo*0746  * memorize current location as "backPop" and go to the "freePush" location.
                0747  * Used only by 1st thread. Not locked */
b4daa24319 Shre*0748 void checkPushInReadOnly() {
                0749   RepetitionLevel *topActive = topRepetitionPoint ;
                0750   while (topActive && !topActive->active) {
                0751     topActive = topActive->previous ;
                0752   }
feb7fa5d1e dngo*0753   if (topActive) {
                0754     if(currentLocationStrictBelowFreePush(topActive)) {
                0755       setBackPopToCurrentLocation(topActive) ;
                0756       setCurrentLocationToFreePush(topActive) ;
                0757 #ifdef ADSTACK_TRACE
b4daa24319 Shre*0758       printf("BEFORE PUSH AT ") ;
                0759       showLocation(topRepetitionPoint->backPopBlock, topRepetitionPoint->backPop) ;
                0760       printf("  WITH REPETITION LEVELS:\n") ;
feb7fa5d1e dngo*0761       dumpRepetitionLevels() ;
b4daa24319 Shre*0762       printf("  MOVE TO FREE PUSH LOCATION ") ;
                0763       showLocation(topRepetitionPoint->freePushBlock, topRepetitionPoint->freePush) ;
                0764       printf("\n") ;
feb7fa5d1e dngo*0765 #endif
                0766     } else if (currentLocationEqualsFreePush(topActive)) {
                0767       //setBackPopToCurrentLocation(topActive) ; //not sure
                0768       setCurrentLocationToFreePush(topActive) ;
                0769 #ifdef ADSTACK_TRACE
                0770       printf("BEFORE PUSH 2 AT ") ;
                0771       showLocation(topRepetitionPoint->backPopBlock, topRepetitionPoint->backPop) ;
                0772       printf("  WITH REPETITION LEVELS:\n") ;
                0773       dumpRepetitionLevels() ;
                0774       printf("  MOVE TO FREE PUSH LOCATION ") ;
                0775       showLocation(topRepetitionPoint->freePushBlock, topRepetitionPoint->freePush) ;
                0776       printf("\n") ;
                0777 #endif
b4daa24319 Shre*0778     }
                0779   }
                0780 }
                0781 
                0782 /** If current location is some "freePush" location,
feb7fa5d1e dngo*0783  * go back to its "backPop" location, which is in a protected, read-only section.
                0784  * Used only by 1st thread. Not locked */
b4daa24319 Shre*0785 void checkPopToReadOnly() {
                0786   RepetitionLevel *repetitionPoint = topRepetitionPoint ;
feb7fa5d1e dngo*0787 #ifdef ADSTACK_TRACE
                0788   RepetitionLevel *activeRepetitionPoint = topRepetitionPoint ;
                0789   while (activeRepetitionPoint && !activeRepetitionPoint->active) {
                0790     activeRepetitionPoint = activeRepetitionPoint->previous ;
                0791   }
                0792   if (activeRepetitionPoint && activeRepetitionPoint->hasBackPop
                0793       && currentLocationEqualsFreePush(activeRepetitionPoint)) {
b4daa24319 Shre*0794     printf("AFTER POP, LOCATION WAS ") ;
                0795     showLocation(curStack, tappos) ;
                0796     printf("  WITH REPETITION LEVELS:\n") ;
feb7fa5d1e dngo*0797     dumpRepetitionLevels() ;
b4daa24319 Shre*0798   }
feb7fa5d1e dngo*0799 #endif
b4daa24319 Shre*0800   int canEraseInactive = 1 ;
                0801   int canRemoveBackPop = 1 ;
                0802   do {
                0803     RepetitionLevel *oldCell = repetitionPoint ;
feb7fa5d1e dngo*0804     if (oldCell->hasBackPop && oldCell->active) {
                0805       if (currentLocationEqualsFreePush(oldCell)) {
                0806         setCurrentLocationToBackPop(oldCell) ;
                0807 #ifdef ADSTACK_TRACE
                0808         printf("  MOVED TO BACK POP LOCATION:") ;
                0809         showLocation(curStack, tappos) ;
                0810         printf("\n") ;
                0811 #endif
                0812         if (canRemoveBackPop) oldCell->hasBackPop = 0 ;
                0813       } else if (currentLocationEqualsBackPop(oldCell)) {
                0814         if (canRemoveBackPop) oldCell->hasBackPop = 0 ;
                0815       }
b4daa24319 Shre*0816     }
                0817     repetitionPoint = oldCell->previous ;
                0818     if (!oldCell->active && canEraseInactive) {
                0819       free(oldCell) ;
                0820       topRepetitionPoint = repetitionPoint ;
                0821     } else {
                0822       canEraseInactive = 0 ;
                0823       canRemoveBackPop = 0 ;
                0824     }
                0825   } while (repetitionPoint) ;
                0826 }
                0827 
                0828 /** From now on, and until the matching closing adStack_endRepeat(),
                0829  * the current contents of the push-pop stack are preserved:
                0830  * Even if they are popped, any subsequent adStack_resetRepeat()
feb7fa5d1e dngo*0831  * will reset the push-pop stack to its current contents of now.
                0832  * Used only by 1st thread. Not locked */
b4daa24319 Shre*0833 void adStack_startRepeat() {
feb7fa5d1e dngo*0834 #ifdef ADSTACK_TRACE
                0835   printf("BEFORE START REPEAT AT ") ;
                0836   showLocation(curStack, tappos) ;
                0837   printf("\n") ;
                0838   dumpRepetitionLevels() ;
                0839   dumpStack(curStack) ; printf("\n") ;
                0840 #endif
b4daa24319 Shre*0841   // Create a new repetition level and push it onto topRepetitionPoint
                0842   RepetitionLevel *newRepetitionLevel = (RepetitionLevel *)malloc(sizeof(RepetitionLevel)) ;
feb7fa5d1e dngo*0843   if (!newRepetitionLevel) {
                0844     printf("Out of memory while creating a RepetitionLevel.\n") ;
                0845     exit(0) ;
                0846   }
b4daa24319 Shre*0847   newRepetitionLevel->previous = topRepetitionPoint ;
                0848   newRepetitionLevel->hasBackPop = 0 ;
                0849   newRepetitionLevel->active = 1 ;
feb7fa5d1e dngo*0850   newRepetitionLevel->backPopBlock = NULL ;
                0851   newRepetitionLevel->backPop = 0 ;
                0852   newRepetitionLevel->resumePointBlock = NULL ;
                0853   newRepetitionLevel->resumePoint = 0 ;
                0854   newRepetitionLevel->freePushBlock = NULL ;
                0855   newRepetitionLevel->freePush = 0 ;
b4daa24319 Shre*0856   // Copy the bits buffer:
                0857   newRepetitionLevel->storedadbitbuf = adbitbuf ;
                0858   newRepetitionLevel->storedadbitibuf = adbitibuf ;
                0859   // In the very weird case where current stack is empty, make it explicit:
                0860   if (curStack==NULL) {
                0861     tapblock = pushBlock() ;
                0862     tappos = 0 ;
                0863   }
                0864   // Store current location as the "resumePoint" location:
                0865   setResumePointToCurrentLocation(newRepetitionLevel) ;
                0866   // Set the "freePush" location to current location OR to
                0867   // the "freePush" of the "enclosing" repetition level,
                0868   // (if there is one and it is higher)
                0869   if (topRepetitionPoint && currentLocationStrictBelowFreePush(topRepetitionPoint)) {
                0870     newRepetitionLevel->freePushBlock = topRepetitionPoint->freePushBlock ;
                0871     newRepetitionLevel->freePush = topRepetitionPoint->freePush ;
                0872   } else {
                0873     setFreePushToCurrentLocation(newRepetitionLevel) ;
                0874   }
                0875   // Make this new repetition level the current repetition level:
                0876   topRepetitionPoint = newRepetitionLevel ;
feb7fa5d1e dngo*0877 #ifdef ADSTACK_TRACE
                0878   printf(">AFTER START REPEAT AT:") ;
                0879   showLocation(curStack, tappos) ;
                0880   printf("\n") ;
                0881   dumpRepetitionLevels() ;
                0882   dumpStack(curStack) ; printf("\n") ;
                0883 #endif
b4daa24319 Shre*0884 }
                0885 
                0886 /** Reset the push-pop stack contents to its contents at
                0887  * the time of the latest adStack_startRepeat() that has not been
feb7fa5d1e dngo*0888  * closed by a subsequent adStack_endRepeat().
                0889  * Used only by 1st thread. Not locked */
b4daa24319 Shre*0890 void adStack_resetRepeat() {
feb7fa5d1e dngo*0891 #ifdef ADSTACK_TRACE
                0892   printf("BEFORE RESET REPEAT AT ") ;
                0893   showLocation(curStack, tappos) ;
                0894   printf("\n") ;
                0895   dumpRepetitionLevels() ;
                0896   dumpStack(curStack) ; printf("\n") ;
                0897 #endif
b4daa24319 Shre*0898   // Remove (pop) all passive deeper repetition levels:
                0899   while (topRepetitionPoint && !topRepetitionPoint->active) {
                0900     RepetitionLevel *oldTop = topRepetitionPoint ;
                0901     topRepetitionPoint = topRepetitionPoint->previous ;
                0902     free(oldTop) ;
                0903   }
                0904   // Reset current location to "resumePoint" location:
                0905   setCurrentLocationToResumePoint(topRepetitionPoint) ;
                0906   // Reset the bits buffer:
                0907   adbitbuf = topRepetitionPoint->storedadbitbuf ;
                0908   adbitibuf = topRepetitionPoint->storedadbitibuf ;
feb7fa5d1e dngo*0909 #ifdef ADSTACK_TRACE
                0910   printf(">AFTER RESET REPEAT AT ") ;
                0911   showLocation(curStack, tappos) ;
                0912   printf("\n") ;
                0913   dumpRepetitionLevels() ;
                0914   dumpStack(curStack) ; printf("\n") ;
                0915 #endif
b4daa24319 Shre*0916 }
                0917 
feb7fa5d1e dngo*0918 /** Close (i.e. remove) the repetition level created by the latest adStack_startRepeat().
                0919  * Used only by 1st thread. Not locked, but contains a locked section */
b4daa24319 Shre*0920 void adStack_endRepeat() {
feb7fa5d1e dngo*0921 #ifdef ADSTACK_TRACE
                0922   printf("BEFORE END REPEAT AT ") ;
                0923   showLocation(curStack, tappos) ;
                0924   printf("\n") ;
                0925   dumpRepetitionLevels() ;
                0926   dumpStack(curStack) ; printf("\n") ;
                0927 #endif
b4daa24319 Shre*0928   // Set to inactive the topmost active repetition level:
                0929   RepetitionLevel *topActive = topRepetitionPoint ;
                0930   while (!topActive->active) {
                0931     topActive = topActive->previous ;
                0932   }
                0933   topActive->active = 0 ;
feb7fa5d1e dngo*0934 
                0935   if (!(topActive->previous!=NULL &&
                0936         topActive->previous->freePushBlock == topActive->freePushBlock)) {
                0937     // i.e. unless this repeat section is a sub-section of the repeat above,
                0938     // remove storage files of all Blocks from the current location
                0939     // (or at least from the freePushBlock of the enclosing repeat) ...
                0940     DoubleChainedBlock *eraseBlockFrom = curStack ;
                0941     if (topActive->previous!=NULL
                0942         && topActive->previous->freePushBlock->next
                0943         && topActive->previous->freePushBlock->next->rank > curStack->rank) {
                0944       eraseBlockFrom = topActive->previous->freePushBlock->next ;
                0945     }
                0946     // ... till the freePushBlock of the currently ended repeat level.
                0947     DoubleChainedBlock *eraseBlockTo = topActive->freePushBlock ;
                0948 #ifdef ADSTACK_TRACE
                0949     printf(" erase all files from %02i up to %02i\n",
                0950            (eraseBlockFrom ? eraseBlockFrom->rank : -1),
                0951            (eraseBlockTo ? eraseBlockTo->rank : -1)) ;
                0952 #endif
                0953 #ifdef ADSTACK_PREFETCH
                0954     // Start a locked section on 1st thread:
                0955     pthread_mutex_lock(&fileStorageMutex) ;
                0956 #endif
                0957     while (eraseBlockFrom) {
                0958       if (eraseBlockFrom->rank!=eraseBlockFrom->toContents->rank) {
                0959         removeStorageFile(eraseBlockFrom->rank) ;
                0960       }
                0961       if (eraseBlockFrom->rank==eraseBlockFrom->toContents->rank) {
                0962         if (eraseBlockFrom->toContents->state==STORED
                0963             || eraseBlockFrom==topActive->freePushBlock) {
                0964           removeStorageFile(eraseBlockFrom->toContents->rank) ;
                0965           eraseBlockFrom->toContents->state = INUSE ;
                0966         }
                0967         if (eraseBlockFrom!=curStack && spaceBeingDone!=eraseBlockFrom->toContents
                0968             && !enqueued(eraseBlockFrom->toContents)) {
                0969           eraseBlockFrom->toContents->rank = 0 ;
                0970           eraseBlockFrom->toContents->state = STORED ;
                0971         }
                0972       }
                0973       if (eraseBlockFrom==eraseBlockTo) {
                0974         eraseBlockFrom = NULL ;
                0975       } else {
                0976         eraseBlockFrom = eraseBlockFrom->next ;
                0977       }
                0978     }
                0979 #ifdef ADSTACK_PREFETCH
                0980     pthread_mutex_unlock(&fileStorageMutex) ;
                0981     // End locked section on 1st thread.
                0982 #endif
                0983   }
b4daa24319 Shre*0984   // current location may have moved back ; check if we must move further back:
                0985   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*0986 #ifdef ADSTACK_TRACE
                0987   printf(">AFTER END REPEAT AT ") ;
                0988   showLocation(curStack, tappos) ;
                0989   printf("\n") ;
                0990   dumpRepetitionLevels() ;
                0991   dumpStack(curStack) ; printf("\n") ;
                0992 #endif
                0993 }
                0994 
                0995 /************** Management of storage in files ***************/
                0996 
                0997 /** Used only by 2nd thread. Not locked */
                0998 void storeInFile(BlockContents* blockContents) {
                0999   sprintf(tapStackFileName, "tapStack%05i\0", blockContents->rank) ;
                1000   FILE *tapStackFile = fopen(tapStackFileName, "wb") ;
                1001   fwrite(blockContents->contents, 1, ADSTACK_BLOCK_SIZE, tapStackFile) ;
                1002   fclose(tapStackFile) ;
                1003 }
                1004 
                1005 /** Used only by 2nd thread. Not locked */
                1006 void restoreFromFile(BlockContents* blockContents /*, RepetitionLevel* repetitionForbidsRemove*/) {
                1007   sprintf(tapStackFileName, "tapStack%05i\0", blockContents->rank) ;
                1008   FILE *tapStackFile = fopen(tapStackFileName, "rb") ;
                1009   fread(blockContents->contents, 1, ADSTACK_BLOCK_SIZE, tapStackFile) ;
                1010   fclose(tapStackFile) ;
                1011 }
                1012 
                1013 /** Used only by 1st thread. Not locked */
                1014 void removeStorageFile(int blockRank) {
                1015   char tapStackFileNameBis[14] ;
                1016   sprintf(tapStackFileNameBis, "tapStack%05i\0", blockRank) ;
                1017 #ifdef ADSTACK_TRACE
                1018   printf("  Remove storage file %s\n", tapStackFileNameBis) ;
                1019 #endif
                1020   remove(tapStackFileNameBis) ;
                1021 }
                1022 
                1023 /** Used only by 1st thread. Not locked. */
                1024 BlockContents* assignSpace(int blockRank) {
                1025   BlockContents* space ;
                1026   int index = (blockRank-1)%ADSTACK_MAX_SPACES ; //index in allBlockContents
                1027   space = allBlockContents[index] ;
                1028   if (!space) {
                1029       space = (BlockContents*)malloc(sizeof(BlockContents)) ;
                1030       if (!space) {
                1031         printf("Out of memory while creating a BlockContents.\n") ;
                1032         exit(0) ;
                1033       }
                1034 #ifdef ADSTACK_TRACE
                1035       space->id = index ;
                1036 #endif
                1037       // Convention: STORED and rank 0 means not in use and ready to be used
                1038       space->rank = 0 ;
                1039       space->state = STORED ;
                1040       allBlockContents[index] = space ;
b4daa24319 Shre*1041   }
feb7fa5d1e dngo*1042   return space ;
                1043 }
                1044 
                1045 #ifdef ADSTACK_PREFETCH
                1046 /** Used only by 2nd thread. Not locked, but contains mostly locked sections. */
                1047 void* manageFileStorage(void *arg) {
                1048   struct timespec ts;
                1049   // Start a locked section on 2nd thread:
                1050   pthread_mutex_lock(&fileStorageMutex) ;
                1051   while (1) {
                1052     while (fileActionQueueHead==NULL) {
                1053 #ifdef ADSTACK_TRACE
                1054       clock_gettime(CLOCK_REALTIME, &ts);
                1055       printf("t%09i------------------ Waiting in manage\n", ts.tv_nsec) ;
                1056 #endif
                1057       int rt = 0 ;
                1058 //    clock_gettime(CLOCK_REALTIME, &ts);
                1059 //    ts.tv_sec += 1;
                1060 //    rt = pthread_cond_timedwait(&enqueuedStorageCV, &fileStorageMutex, &ts) ;
                1061       pthread_cond_wait(&enqueuedStorageCV, &fileStorageMutex) ;
                1062 #ifdef ADSTACK_TRACE
                1063       clock_gettime(CLOCK_REALTIME, &ts);
                1064       printf("t%09i------------------ Wait %s in manage\n", ts.tv_nsec, (rt ? "timed out" : "woke up")) ;
                1065 #endif
                1066     }
                1067 #ifdef ADSTACK_TRACE
                1068     clock_gettime(CLOCK_REALTIME, &ts);
                1069     printf("t%09i------------------ Manage file action queue:", ts.tv_nsec) ; dumpFileActionQueue() ; printf("\n") ;
                1070 #endif
                1071     fileActionBeingDone = fileActionQueueHead->action ;
                1072     if (fileActionBeingDone==STORE) {
                1073       spaceBeingDone = popHeadFileAction() ;
                1074       rankBeingDone = spaceBeingDone->rank ;
                1075     } else {
                1076       rankBeingDone = fileActionQueueHead->restoredRank ;
                1077       spaceBeingDone = popHeadFileAction() ;
                1078       spaceBeingDone->rank = rankBeingDone ;
                1079     }
                1080     pthread_mutex_unlock(&fileStorageMutex) ;
                1081     // End locked section on 2nd thread.
                1082 #ifdef ADSTACK_TRACE
                1083     clock_gettime(CLOCK_REALTIME, &ts);
                1084     if (fileActionBeingDone==STORE) {
                1085       printf("t%09i------------------ Going to store %04i from (%c: %02i %s)\n", ts.tv_nsec,
                1086              spaceBeingDone->rank,
                1087              'a'+spaceBeingDone->id,
                1088              spaceBeingDone->rank,
                1089              stateNames[spaceBeingDone->state]) ;
                1090     } else if (fileActionBeingDone==RESTORE) {
                1091       printf("t%09i------------------ Going to restore %04i into (%c: %02i %s)\n", ts.tv_nsec,
                1092              spaceBeingDone->rank, //restoredRank,
                1093              'a'+spaceBeingDone->id,
                1094              spaceBeingDone->rank,
                1095              stateNames[spaceBeingDone->state]) ;
                1096     }
                1097 #endif
                1098     if (fileActionBeingDone==STORE) {
                1099       storeInFile(spaceBeingDone) ;
                1100     } else if (fileActionBeingDone==RESTORE) {
                1101       restoreFromFile(spaceBeingDone) ;
                1102     }
                1103     // Start a locked section on 2nd thread:
                1104     pthread_mutex_lock(&fileStorageMutex) ;
                1105     spaceBeingDone->state = STORED ;
                1106 #ifdef ADSTACK_TRACE
                1107     struct timespec ts;
                1108     clock_gettime(CLOCK_REALTIME, &ts);
                1109     printf("t%09i------------------ %s (%c: %02i %s) done, send signal doneStoreOrRestoreCV\n",
                1110            ts.tv_nsec, (fileActionBeingDone==STORE ? "Store" : "Restore"),
                1111            'a'+spaceBeingDone->id,
                1112            spaceBeingDone->rank, stateNames[spaceBeingDone->state]) ;
                1113 #endif
                1114     fileActionBeingDone = NOACTION ;
                1115     spaceBeingDone = NULL ;
                1116     rankBeingDone = -1 ;
                1117     pthread_cond_signal(&doneStoreOrRestoreCV) ;
                1118   }
                1119   pthread_mutex_unlock(&fileStorageMutex) ;
                1120   // End locked section on 2nd thread.
b4daa24319 Shre*1121 }
feb7fa5d1e dngo*1122 #endif
b4daa24319 Shre*1123 
feb7fa5d1e dngo*1124 /***************** Standard management of the stack *************/
b4daa24319 Shre*1125 
feb7fa5d1e dngo*1126 /** Push a data block onto the stack
                1127  * Used only by 1st thread. Not locked, but contains a locked section. */
b4daa24319 Shre*1128 char* pushBlock() {
feb7fa5d1e dngo*1129   struct timespec ts;
b4daa24319 Shre*1130   if (curStack && curStack->next) {
                1131     curStack = curStack->next ;
                1132   } else {
                1133     DoubleChainedBlock *newStack = (DoubleChainedBlock*)malloc(sizeof(DoubleChainedBlock)) ;
feb7fa5d1e dngo*1134     if (!newStack) {
                1135       printf("Out of memory while creating a DoubleChainedBlock.\n") ;
b4daa24319 Shre*1136       exit(0) ;
                1137     }
feb7fa5d1e dngo*1138     newStack->toContents = NULL ;
b4daa24319 Shre*1139     if(curStack != NULL) {
                1140       curStack->next = newStack ;
                1141       newStack->rank = curStack->rank + 1 ;
                1142     } else {
                1143       newStack->rank = 1 ;
feb7fa5d1e dngo*1144 #ifdef ADSTACK_PREFETCH
                1145       // INITIALIZE THINGS AND LAUNCH THE 2nd THREAD:
                1146       int errCode = 0 ;
                1147       if ((errCode = pthread_mutex_init(&fileStorageMutex, NULL)) != 0) {
                1148           printf("Error creating mutex. Error code:%i\n", errCode) ;
                1149       }
                1150       if ((errCode = pthread_cond_init(&enqueuedStorageCV, NULL)) != 0) {
                1151           printf("Error creating condition variable enqueuedStorageCV. Error code:%i\n", errCode) ;
                1152       }
                1153       if ((errCode = pthread_cond_init(&doneStoreOrRestoreCV, NULL)) != 0) {
                1154           printf("Error creating condition variable doneStoreOrRestoreCV. Error code:%i\n", errCode) ;
                1155       }
                1156       if ((errCode = pthread_create(&fileStorageThread, NULL, manageFileStorage, NULL)) != 0) {
                1157           printf("Error creating thread. Error code:%i\n", errCode) ;
                1158       }
                1159 #endif
b4daa24319 Shre*1160     }
feb7fa5d1e dngo*1161     newStack->toContents = NULL ;
b4daa24319 Shre*1162     newStack->prev = curStack ;
                1163     newStack->next = NULL ;
                1164     curStack = newStack ;
                1165   }
feb7fa5d1e dngo*1166   BlockContents *space = curStack->toContents ;
                1167   if (!space) {
                1168     space = assignSpace(curStack->rank);
                1169     curStack->toContents = space ;
                1170   }
                1171 #ifdef ADSTACK_PREFETCH
                1172   // Start a locked section on 1st thread:
                1173   pthread_mutex_lock(&fileStorageMutex) ;
                1174   preStore() ;
                1175   waitForward() ;
                1176   space->state = INUSE ;
                1177   space->rank = curStack->rank ;
                1178   pthread_mutex_unlock(&fileStorageMutex) ;
                1179   // End locked section on 1st thread.
                1180 #else
                1181   checkForward() ;
                1182   space->state = INUSE ;
                1183   space->rank = curStack->rank ;
                1184 #endif
                1185 #ifdef ADSTACK_TRACE
                1186   clock_gettime(CLOCK_REALTIME, &ts);
                1187   printf("t%09i %02i => %02i\n", ts.tv_nsec, curStack->rank - 1,
                1188          curStack->rank) ;
                1189   dumpStack(curStack) ; printf("\n") ;
                1190 #endif
                1191 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1192   if (curStack->rank > maxBlocks) maxBlocks = curStack->rank ;
                1193 #endif
feb7fa5d1e dngo*1194   return space->contents ;
b4daa24319 Shre*1195 }
                1196 
feb7fa5d1e dngo*1197 /** Pop the data block at top
                1198  * Used only by 1st thread. Not locked, but contains a locked section. */
b4daa24319 Shre*1199 char* popBlock() {
                1200   DoubleChainedBlock *oldTopStack = curStack ;
feb7fa5d1e dngo*1201   struct timespec ts;
b4daa24319 Shre*1202   curStack = curStack->prev ;
feb7fa5d1e dngo*1203 #ifdef ADSTACK_PREFETCH
                1204   // Start a locked section on 1st thread:
                1205   pthread_mutex_lock(&fileStorageMutex) ;
                1206   int oldInRepetition =
                1207     (topRepetitionPoint && oldTopStack->rank <= topRepetitionPoint->freePushBlock->rank) ;
                1208   if (!oldInRepetition && spaceBeingDone!=oldTopStack->toContents
                1209       && !enqueued(oldTopStack->toContents)) {
                1210       oldTopStack->toContents->rank = 0 ;
                1211       oldTopStack->toContents->state = STORED ;
                1212     }
                1213   preRestore() ;
                1214   waitBackward() ;
                1215   if (!topRepetitionPoint || curStack->rank >= topRepetitionPoint->freePushBlock->rank) {
                1216     if ((!topRepetitionPoint || curStack != topRepetitionPoint->freePushBlock)
                1217         && curStack->toContents->state==STORED) {
                1218       removeStorageFile(curStack->toContents->rank) ;
b4daa24319 Shre*1219     }
feb7fa5d1e dngo*1220     // because we are going to pop from curStack then possibly push again:
                1221     curStack->toContents->state = INUSE ;
b4daa24319 Shre*1222   }
feb7fa5d1e dngo*1223   curStack->toContents->rank = curStack->rank ;
                1224   pthread_mutex_unlock(&fileStorageMutex) ;
                1225   // End locked section on 1st thread.
                1226 #else
                1227   int oldInRepetition =
                1228     (topRepetitionPoint && oldTopStack->rank <= topRepetitionPoint->freePushBlock->rank) ;
                1229   if (!oldInRepetition && spaceBeingDone!=oldTopStack->toContents
                1230       && !enqueued(oldTopStack->toContents)) {
                1231       oldTopStack->toContents->rank = 0 ;
                1232       oldTopStack->toContents->state = STORED ;
                1233     }
                1234   checkBackward() ;
                1235   if (!topRepetitionPoint || curStack->rank >= topRepetitionPoint->freePushBlock->rank) {
                1236     if ((!topRepetitionPoint || curStack != topRepetitionPoint->freePushBlock)
                1237         && curStack->toContents->state==STORED) {
                1238       removeStorageFile(curStack->toContents->rank) ;
                1239     }
                1240     // because we are going to pop from curStack then possibly push again:
                1241     curStack->toContents->state = INUSE ;
                1242   }
                1243   curStack->toContents->rank = curStack->rank ;
                1244 #endif
                1245 #ifdef ADSTACK_TRACE
                1246   clock_gettime(CLOCK_REALTIME, &ts);
                1247   printf("t%09i %02i <= %02i\n", ts.tv_nsec, curStack->rank, curStack->rank + 1) ;
                1248   dumpStack(curStack) ; printf("\n") ;
                1249 #endif
                1250   return (curStack ? curStack->toContents->contents : NULL) ;
b4daa24319 Shre*1251 }
                1252 
feb7fa5d1e dngo*1253 /********************* Array push/pop functions ***********************/
                1254 
                1255 // All routines below are used only by 1st thread. Not locked.
b4daa24319 Shre*1256 
                1257 /* pushNArray/popNArray are used not only to store arrays of various data
                1258    types. These functions are also the only ones that interact with the dynamic
                1259    memory management, e.g. requesting new blocks. If one of the scalar push/pop
                1260    functions (e.g. pushReal4) encounters the end of a block, it will ask
                1261    pushNArray to do all the work, i.e. start a new block and push the real4
                1262    value to it. */
                1263 void pushNArray(char *x, int nbChars) {
                1264   do {
feb7fa5d1e dngo*1265     int wsize = tappos+nbChars<ADSTACK_BLOCK_SIZE?nbChars:ADSTACK_BLOCK_SIZE-tappos ;
b4daa24319 Shre*1266     if(wsize > 0) {
                1267       memcpy(tapblock+tappos,x,wsize) ;
                1268       nbChars -= wsize ;
                1269       x += wsize ;
                1270       tappos += wsize ;
                1271     }
                1272     else if (nbChars > 0) {
                1273       tapblock = pushBlock() ;
                1274       tappos = 0 ;
                1275     }
                1276   } while(nbChars > 0) ; //=> lazy push: if finishes at the top of block contents, does not push a new block.
                1277 }
                1278 
                1279 void popNArray(char *x, int nbChars) {
                1280   x += nbChars ;
                1281   do {
                1282     int wsize = (nbChars<tappos)?nbChars:tappos ;
                1283     if(wsize > 0) {
                1284       memcpy(x-wsize,tapblock+tappos-wsize,wsize) ;
                1285       nbChars -= wsize ;
                1286       x -= wsize ;
                1287       tappos -= wsize ;
                1288     }
                1289     else if (nbChars > 0) {
                1290       tapblock = popBlock() ;
feb7fa5d1e dngo*1291       tappos = ADSTACK_BLOCK_SIZE ;
b4daa24319 Shre*1292     }
                1293   } while(nbChars > 0) ; //=> lazy pop: if finishes at the bottom of block contents, does not pop block.
                1294 }
                1295 
                1296 void pushInteger4Array(int *x, int n) {
                1297   if (topRepetitionPoint) checkPushInReadOnly() ;
                1298   pushNArray((char *)x,(int)(n*4)) ;
feb7fa5d1e dngo*1299 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1300   pushPopTraffic += (int)(n*4) ;
                1301 #endif
                1302 }
                1303 
                1304 void popInteger4Array(int *x, int n) {
                1305   popNArray((char *)x,(int)(n*4)) ;
                1306   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1307 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1308   pushPopTraffic += (int)(n*4) ;
                1309 #endif
                1310 }
                1311 
                1312 void pushInteger8Array(long *x, int n) {
                1313   if (topRepetitionPoint) checkPushInReadOnly() ;
                1314   pushNArray((char *)x,(int)(n*8)) ;
feb7fa5d1e dngo*1315 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1316   pushPopTraffic += (int)(n*8) ;
                1317 #endif
                1318 }
                1319 
                1320 void popInteger8Array(long *x, int n) {
                1321   popNArray((char *)x,(int)(n*8)) ;
                1322   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1323 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1324   pushPopTraffic += (int)(n*8) ;
                1325 #endif
                1326 }
                1327 
                1328 void pushReal4Array(float *x, int n) {
                1329   if (topRepetitionPoint) checkPushInReadOnly() ;
                1330   pushNArray((char *)x,(int)(n*4)) ;
feb7fa5d1e dngo*1331 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1332   pushPopTraffic += (int)(n*4) ;
                1333 #endif
                1334 }
                1335 
                1336 void popReal4Array(float *x, int n) {
                1337   popNArray((char *)x,(int)(n*4)) ;
                1338   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1339 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1340   pushPopTraffic += (int)(n*4) ;
                1341 #endif
                1342 }
                1343 
                1344 void pushReal8Array(double *x, int n) {
                1345   if (topRepetitionPoint) checkPushInReadOnly() ;
                1346   pushNArray((char *)x,(int)(n*8)) ;
feb7fa5d1e dngo*1347 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1348   pushPopTraffic += (int)(n*8) ;
                1349 #endif
                1350 }
                1351 
                1352 void popReal8Array(double *x, int n) {
                1353   popNArray((char *)x,(int)(n*8)) ;
                1354   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1355 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1356   pushPopTraffic += (int)(n*8) ;
                1357 #endif
                1358 }
                1359 
feb7fa5d1e dngo*1360 void pushReal16Array(long double *x, int n) {
                1361   if (topRepetitionPoint) checkPushInReadOnly() ;
                1362   pushNArray((char *)x,(int)(n*16)) ;
                1363 #ifdef ADSTACK_PROFILE
                1364   pushPopTraffic += (int)(n*16) ;
                1365 #endif
                1366 }
                1367 
                1368 void popReal16Array(long double *x, int n) {
                1369   popNArray((char *)x,(int)(n*16)) ;
                1370   if (topRepetitionPoint) checkPopToReadOnly() ;
                1371 #ifdef ADSTACK_PROFILE
                1372   pushPopTraffic += (int)(n*16) ;
                1373 #endif
                1374 }
                1375 
b4daa24319 Shre*1376 void pushComplex8Array(ccmplx *x, int n) {
                1377   if (topRepetitionPoint) checkPushInReadOnly() ;
                1378   pushNArray((char *)x,(int)(n*8)) ;
feb7fa5d1e dngo*1379 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1380   pushPopTraffic += (int)(n*8) ;
                1381 #endif
                1382 }
                1383 
                1384 void popComplex8Array(ccmplx *x, int n) {
                1385   popNArray((char *)x,(int)(n*8)) ;
                1386   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1387 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1388   pushPopTraffic += (int)(n*8) ;
                1389 #endif
                1390 }
                1391 
                1392 void pushComplex16Array(double complex *x, int n) {
                1393   if (topRepetitionPoint) checkPushInReadOnly() ;
                1394   pushNArray((char *)x,(int)(n*16)) ;
feb7fa5d1e dngo*1395 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1396   pushPopTraffic += (int)(n*16) ;
                1397 #endif
                1398 }
                1399 
                1400 void popComplex16Array(double complex *x, int n) {
                1401   popNArray((char *)x,(int)(n*16)) ;
                1402   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1403 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1404   pushPopTraffic += (int)(n*16) ;
                1405 #endif
                1406 }
                1407 
                1408 void pushCharacterArray(char *x, int n) {
                1409   if (topRepetitionPoint) checkPushInReadOnly() ;
                1410   pushNArray(x,(int)n) ;
feb7fa5d1e dngo*1411 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1412   pushPopTraffic += (int)n ;
                1413 #endif
                1414 }
                1415 
                1416 void popCharacterArray(char *x, int n) {
                1417   popNArray(x,(int)n) ;
                1418   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1419 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1420   pushPopTraffic += (int)n ;
                1421 #endif
                1422 }
                1423 
feb7fa5d1e dngo*1424 /***************** Scalar push/pop functions *****************/
b4daa24319 Shre*1425 
                1426 void pushCharacter(char val) {
                1427   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1428   if(tappos + 1 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1429     pushNArray((char*)&val, 1) ;
                1430   }
                1431   else {
                1432     *(char*)(tapblock+tappos) = val;
                1433     tappos = tappos + 1 ;
                1434   }
feb7fa5d1e dngo*1435 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1436   pushPopTraffic += 1 ;
                1437 #endif
                1438 }
                1439 
                1440 void popCharacter(char * val) {
                1441   if(tappos - 1 < 0) {
                1442     popNArray((char*)val, 1) ;
                1443   }
                1444   else {
                1445     tappos = tappos - 1 ;
                1446     *val = *(char*)(tapblock+tappos);
                1447   }
                1448   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1449 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1450   pushPopTraffic += 1 ;
                1451 #endif
                1452 }
                1453 
                1454 void pushReal4(float val) {
                1455   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1456   if(tappos + 4 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1457     pushNArray((char*)&val, 4) ;
                1458   }
                1459   else {
                1460     *(float*)(tapblock+tappos) = val;
                1461     tappos = tappos + 4 ;
                1462   }
feb7fa5d1e dngo*1463 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1464   pushPopTraffic += 4 ;
                1465 #endif
                1466 }
                1467 
                1468 void popReal4(float * val) {
                1469   if(tappos - 4 < 0) {
                1470     popNArray((char*)val, 4) ;
                1471   }
                1472   else {
                1473     tappos = tappos - 4 ;
                1474     *val = *(float*)(tapblock+tappos);
                1475   }
                1476   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1477 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1478   pushPopTraffic += 4 ;
                1479 #endif
                1480 }
                1481 
                1482 void pushReal8(double val) {
                1483   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1484   if(tappos + 8 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1485     pushNArray((char*)&val, 8) ;
                1486   }
                1487   else {
                1488     *(double*)(tapblock+tappos) = val;
                1489     tappos = tappos + 8 ;
                1490   }
feb7fa5d1e dngo*1491 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1492   pushPopTraffic += 8 ;
                1493 #endif
                1494 }
                1495 
                1496 void popReal8(double * val) {
                1497   if(tappos - 8 < 0) {
                1498     popNArray((char*)val, 8) ;
                1499   }
                1500   else {
                1501     tappos = tappos - 8 ;
                1502     *val = *(double*)(tapblock+tappos);
                1503   }
                1504   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1505 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1506   pushPopTraffic += 8 ;
                1507 #endif
                1508 }
                1509 
feb7fa5d1e dngo*1510 void pushReal16(long double *val) {
                1511   if (topRepetitionPoint) checkPushInReadOnly() ;
                1512   if(tappos + 16 > ADSTACK_BLOCK_SIZE) {
                1513     pushNArray((char*)val, 16) ;
                1514   }
                1515   else {
                1516     memcpy(tapblock+tappos, (void *)val, 16);
                1517     tappos = tappos + 16 ;
                1518   }
                1519 #ifdef ADSTACK_PROFILE
                1520   pushPopTraffic += 16 ;
                1521 #endif
                1522 }
                1523 
                1524 void popReal16(long double *val) {
                1525   if(tappos - 16 < 0) {
                1526     popNArray((char*)val, 16) ;
                1527   }
                1528   else {
                1529     tappos = tappos - 16 ;
                1530     memcpy((void *)val, tapblock+tappos, 16) ;
                1531   }
                1532   if (topRepetitionPoint) checkPopToReadOnly() ;
                1533 #ifdef ADSTACK_PROFILE
                1534   pushPopTraffic += 16 ;
                1535 #endif
                1536 }
                1537 
b4daa24319 Shre*1538 void pushInteger4(int val) {
                1539   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1540   if(tappos + 4 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1541     pushNArray((char*)&val, 4) ;
                1542   }
                1543   else {
                1544     *(int*)(tapblock+tappos) = val;
                1545     tappos = tappos + 4 ;
                1546   }
feb7fa5d1e dngo*1547 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1548   pushPopTraffic += 4 ;
                1549 #endif
                1550 }
                1551 
                1552 void popInteger4(int * val) {
                1553   if(tappos - 4 < 0) {
                1554     popNArray((char*)val, 4) ;
                1555   }
                1556   else {
                1557     tappos = tappos - 4 ;
                1558     *val = *(int*)(tapblock+tappos);
                1559   }
                1560   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1561 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1562   pushPopTraffic += 4 ;
                1563 #endif
                1564 }
                1565 
                1566 void pushInteger8(long val) {
                1567   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1568   if(tappos + 8 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1569     pushNArray((char*)&val, 8) ;
                1570   }
                1571   else {
                1572     *(long*)(tapblock+tappos) = val;
                1573     tappos = tappos + 8 ;
                1574   }
feb7fa5d1e dngo*1575 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1576   pushPopTraffic += 8 ;
                1577 #endif
                1578 }
                1579 
                1580 void popInteger8(long * val) {
                1581   if(tappos - 8 < 0) {
                1582     popNArray((char*)val, 8) ;
                1583   }
                1584   else {
                1585     tappos = tappos - 8 ;
                1586     *val = *(long*)(tapblock+tappos);
                1587   }
                1588   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1589 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1590   pushPopTraffic += 8 ;
                1591 #endif
                1592 }
                1593 
                1594 void pushComplex8(ccmplx val) {
                1595   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1596   if(tappos + 8 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1597     pushNArray((char*)&val, 8) ;
                1598   }
                1599   else {
                1600     *(ccmplx*)(tapblock+tappos) = val;
                1601     tappos = tappos + 8 ;
                1602   }
feb7fa5d1e dngo*1603 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1604   pushPopTraffic += 8 ;
                1605 #endif
                1606 }
                1607 
                1608 void popComplex8(ccmplx * val) {
                1609   if(tappos - 8 < 0) {
                1610     popNArray((char*)val, 8) ;
                1611   }
                1612   else {
                1613     tappos = tappos - 8 ;
                1614     *val = *(ccmplx*)(tapblock+tappos);
                1615   }
                1616   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1617 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1618   pushPopTraffic += 8 ;
                1619 #endif
                1620 }
                1621 
                1622 void pushComplex16(double complex val) {
                1623   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1624   if(tappos + 16 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1625     pushNArray((char*)&val, 16) ;
                1626   }
                1627   else {
                1628     *(double complex *)(tapblock+tappos) = val;
                1629     tappos = tappos + 16 ;
                1630   }
feb7fa5d1e dngo*1631 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1632   pushPopTraffic += 16 ;
                1633 #endif
                1634 }
                1635 
                1636 void popComplex16(double complex *val) {
                1637   if(tappos - 16 < 0) {
                1638     popNArray((char*)val, 16) ;
                1639   }
                1640   else {
                1641     tappos = tappos - 16 ;
                1642     *val = *(double complex *)(tapblock+tappos);
                1643   }
                1644   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1645 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1646   pushPopTraffic += 16 ;
                1647 #endif
                1648 }
                1649 
                1650 void pushPointer4(void * val) {
                1651   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1652   if(tappos + 4 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1653     pushNArray((char*)&val, 4) ;
                1654   }
                1655   else {
                1656     *(void**)(tapblock+tappos) = val;
                1657     tappos = tappos + 4 ;
                1658   }
feb7fa5d1e dngo*1659 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1660   pushPopTraffic += 4 ;
                1661 #endif
                1662 }
                1663 
                1664 void popPointer4(void ** val) {
                1665   if(tappos - 4 < 0) {
                1666     popNArray((char*)val, 4) ;
                1667   }
                1668   else {
                1669     tappos = tappos - 4 ;
                1670     *val = *(void**)(tapblock+tappos);
                1671   }
                1672   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1673 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1674   pushPopTraffic += 4 ;
                1675 #endif
                1676 }
                1677 
                1678 void pushPointer8(void * val) {
                1679   if (topRepetitionPoint) checkPushInReadOnly() ;
feb7fa5d1e dngo*1680   if(tappos + 8 > ADSTACK_BLOCK_SIZE) {
b4daa24319 Shre*1681     pushNArray((char*)&val, 8) ;
                1682   }
                1683   else {
                1684     *(void**)(tapblock+tappos) = val;
                1685     tappos = tappos + 8 ;
                1686   }
feb7fa5d1e dngo*1687 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1688   pushPopTraffic += 8 ;
                1689 #endif
                1690 }
                1691 
                1692 void popPointer8(void ** val) {
                1693   if(tappos - 8 < 0) {
                1694     popNArray((char*)val, 8) ;
                1695   }
                1696   else {
                1697     tappos = tappos - 8 ;
                1698     *val = *(void**)(tapblock+tappos);
                1699   }
                1700   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*1701 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1702   pushPopTraffic += 8 ;
                1703 #endif
                1704 }
                1705 
feb7fa5d1e dngo*1706 /******************* Bit (hidden primitives) ***************/
b4daa24319 Shre*1707 
                1708 void pushBit(int x) {
                1709   adbitbuf<<=1 ;
                1710   if (x) ++adbitbuf ;
                1711   if (adbitibuf>=31) {
                1712     pushNArray((char *)&adbitbuf, 4) ;
                1713     adbitbuf = 0 ;
                1714     adbitibuf = 0 ;
feb7fa5d1e dngo*1715 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1716     pushPopTraffic += 4 ;
                1717 #endif
                1718   } else
                1719     ++adbitibuf ;
                1720 }
                1721 
                1722 int popBit() {
                1723   if (adbitibuf<=0) {
                1724     popNArray((char *)&adbitbuf, 4) ;
                1725     adbitibuf = 31 ;
feb7fa5d1e dngo*1726 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*1727     pushPopTraffic += 4 ;
                1728 #endif
                1729   } else
                1730     --adbitibuf ;
                1731   int result = adbitbuf%2 ;
                1732   adbitbuf>>=1 ;
                1733   return result ;
                1734 }
                1735 
feb7fa5d1e dngo*1736 /*************************** Boolean *************************/
b4daa24319 Shre*1737 
                1738 void pushBoolean(int x) {
                1739   if (topRepetitionPoint) checkPushInReadOnly() ;
                1740   pushBit(x) ;
                1741 }
                1742 
                1743 //[llh] I have a bug here: the boolean returned to Fortran is bizarre!
                1744 void popBoolean(int *x) {
                1745   *x = popBit() ;
                1746   if (topRepetitionPoint) checkPopToReadOnly() ;
                1747 }
                1748 
feb7fa5d1e dngo*1749 /************************* Control ***********************/
b4daa24319 Shre*1750 
                1751 void pushControl1b(int cc) {
                1752   if (topRepetitionPoint) checkPushInReadOnly() ;
                1753   pushBit(cc) ;
                1754 }
                1755 
                1756 void popControl1b(int *cc) {
                1757   *cc = popBit() ;
                1758   if (topRepetitionPoint) checkPopToReadOnly() ;
                1759 }
                1760 
                1761 void pushControl2b(int cc) {
                1762   if (topRepetitionPoint) checkPushInReadOnly() ;
                1763   pushBit(cc%2) ;
                1764   cc>>=1 ;
                1765   pushBit(cc) ;
                1766 }
                1767 
                1768 void popControl2b(int *cc) {
                1769   *cc = (popBit()?2:0) ;
                1770   if (popBit()) (*cc)++ ;
                1771   if (topRepetitionPoint) checkPopToReadOnly() ;
                1772 }
                1773 
                1774 void pushControl3b(int cc) {
                1775   if (topRepetitionPoint) checkPushInReadOnly() ;
                1776   pushBit(cc%2) ;
                1777   cc>>=1 ;
                1778   pushBit(cc%2) ;
                1779   cc>>=1 ;
                1780   pushBit(cc) ;
                1781 }
                1782 
                1783 void popControl3b(int *cc) {
                1784   *cc = (popBit()?2:0) ;
                1785   if (popBit()) (*cc)++ ;
                1786   (*cc) <<= 1 ;
                1787   if (popBit()) (*cc)++ ;
                1788   if (topRepetitionPoint) checkPopToReadOnly() ;
                1789 }
                1790 
                1791 void pushControl4b(int cc) {
                1792   if (topRepetitionPoint) checkPushInReadOnly() ;
                1793   pushBit(cc%2) ;
                1794   cc>>=1 ;
                1795   pushBit(cc%2) ;
                1796   cc>>=1 ;
                1797   pushBit(cc%2) ;
                1798   cc>>=1 ;
                1799   pushBit(cc) ;
                1800 }
                1801 
                1802 void popControl4b(int *cc) {
                1803   *cc = (popBit()?2:0) ;
                1804   if (popBit()) (*cc)++ ;
                1805   (*cc) <<= 1 ;
                1806   if (popBit()) (*cc)++ ;
                1807   (*cc) <<= 1 ;
                1808   if (popBit()) (*cc)++ ;
                1809   if (topRepetitionPoint) checkPopToReadOnly() ;
                1810 }
                1811 
                1812 void pushControl5b(int cc) {
                1813   if (topRepetitionPoint) checkPushInReadOnly() ;
                1814   pushBit(cc%2) ;
                1815   cc>>=1 ;
                1816   pushBit(cc%2) ;
                1817   cc>>=1 ;
                1818   pushBit(cc%2) ;
                1819   cc>>=1 ;
                1820   pushBit(cc%2) ;
                1821   cc>>=1 ;
                1822   pushBit(cc) ;
                1823 }
                1824 
                1825 void popControl5b(int *cc) {
                1826   *cc = (popBit()?2:0) ;
                1827   if (popBit()) (*cc)++ ;
                1828   (*cc) <<= 1 ;
                1829   if (popBit()) (*cc)++ ;
                1830   (*cc) <<= 1 ;
                1831   if (popBit()) (*cc)++ ;
                1832   (*cc) <<= 1 ;
                1833   if (popBit()) (*cc)++ ;
                1834   if (topRepetitionPoint) checkPopToReadOnly() ;
                1835 }
                1836 
                1837 void pushControl6b(int cc) {
                1838   if (topRepetitionPoint) checkPushInReadOnly() ;
                1839   pushBit(cc%2) ;
                1840   cc>>=1 ;
                1841   pushBit(cc%2) ;
                1842   cc>>=1 ;
                1843   pushBit(cc%2) ;
                1844   cc>>=1 ;
                1845   pushBit(cc%2) ;
                1846   cc>>=1 ;
                1847   pushBit(cc%2) ;
                1848   cc>>=1 ;
                1849   pushBit(cc) ;
                1850 }
                1851 
                1852 void popControl6b(int *cc) {
                1853   *cc = (popBit()?2:0) ;
                1854   if (popBit()) (*cc)++ ;
                1855   (*cc) <<= 1 ;
                1856   if (popBit()) (*cc)++ ;
                1857   (*cc) <<= 1 ;
                1858   if (popBit()) (*cc)++ ;
                1859   (*cc) <<= 1 ;
                1860   if (popBit()) (*cc)++ ;
                1861   (*cc) <<= 1 ;
                1862   if (popBit()) (*cc)++ ;
                1863   if (topRepetitionPoint) checkPopToReadOnly() ;
                1864 }
                1865 
                1866 void pushControl7b(int cc) {
                1867   if (topRepetitionPoint) checkPushInReadOnly() ;
                1868   pushBit(cc%2) ;
                1869   cc>>=1 ;
                1870   pushBit(cc%2) ;
                1871   cc>>=1 ;
                1872   pushBit(cc%2) ;
                1873   cc>>=1 ;
                1874   pushBit(cc%2) ;
                1875   cc>>=1 ;
                1876   pushBit(cc%2) ;
                1877   cc>>=1 ;
                1878   pushBit(cc%2) ;
                1879   cc>>=1 ;
                1880   pushBit(cc) ;
                1881 }
                1882 
                1883 void popControl7b(int *cc) {
                1884   *cc = (popBit()?2:0) ;
                1885   if (popBit()) (*cc)++ ;
                1886   (*cc) <<= 1 ;
                1887   if (popBit()) (*cc)++ ;
                1888   (*cc) <<= 1 ;
                1889   if (popBit()) (*cc)++ ;
                1890   (*cc) <<= 1 ;
                1891   if (popBit()) (*cc)++ ;
                1892   (*cc) <<= 1 ;
                1893   if (popBit()) (*cc)++ ;
                1894   (*cc) <<= 1 ;
                1895   if (popBit()) (*cc)++ ;
                1896   if (topRepetitionPoint) checkPopToReadOnly() ;
                1897 }
                1898 
                1899 void pushControl8b(int cc) {
                1900   if (topRepetitionPoint) checkPushInReadOnly() ;
                1901   pushBit(cc%2) ;
                1902   cc>>=1 ;
                1903   pushBit(cc%2) ;
                1904   cc>>=1 ;
                1905   pushBit(cc%2) ;
                1906   cc>>=1 ;
                1907   pushBit(cc%2) ;
                1908   cc>>=1 ;
                1909   pushBit(cc%2) ;
                1910   cc>>=1 ;
                1911   pushBit(cc%2) ;
                1912   cc>>=1 ;
                1913   pushBit(cc%2) ;
                1914   cc>>=1 ;
                1915   pushBit(cc) ;
                1916 }
                1917 
                1918 void popControl8b(int *cc) {
                1919   *cc = (popBit()?2:0) ;
                1920   if (popBit()) (*cc)++ ;
                1921   (*cc) <<= 1 ;
                1922   if (popBit()) (*cc)++ ;
                1923   (*cc) <<= 1 ;
                1924   if (popBit()) (*cc)++ ;
                1925   (*cc) <<= 1 ;
                1926   if (popBit()) (*cc)++ ;
                1927   (*cc) <<= 1 ;
                1928   if (popBit()) (*cc)++ ;
                1929   (*cc) <<= 1 ;
                1930   if (popBit()) (*cc)++ ;
                1931   (*cc) <<= 1 ;
                1932   if (popBit()) (*cc)++ ;
                1933   if (topRepetitionPoint) checkPopToReadOnly() ;
                1934 }
                1935 
feb7fa5d1e dngo*1936 uint64_t adStack_getCurrentStackSize() {
                1937  return curStack ? (curStack->rank-1)*ADSTACK_BLOCK_SIZE + tappos : 0;
                1938 }
                1939 
                1940 /******** Various dump routines for profiling and debugging *********/
                1941 
                1942 void showLocation(DoubleChainedBlock *locBlock, int loc) {
                1943   printf("%1i.%05i", (locBlock ? locBlock->rank-1 : 0), loc) ;
                1944 }
                1945 
                1946 #ifdef ADSTACK_TRACE
                1947 void dumpStackPrev(DoubleChainedBlock *st) {
                1948   if (st) {
                1949     if (st->rank==st->toContents->rank) { // Don't dump too far back...
                1950       dumpStackPrev(st->prev) ;
                1951     }
                1952     printf("-->[%02i ", st->rank) ;
                1953     if (st->toContents) {
                1954       printf("(%c: %02i %s)",
                1955              'a'+st->toContents->id,
                1956              st->toContents->rank,
                1957              stateNames[st->toContents->state]) ;
                1958     } else {
                1959       printf("null") ;
                1960     }
                1961     printf("]") ;
                1962   }
                1963 }
                1964 
                1965 void dumpStackNext(DoubleChainedBlock *st) {
                1966   if (st) {
                1967     printf("..>[%02i ", st->rank) ;
                1968     if (st->toContents) {
                1969       printf("(%c: %02i %s)",
                1970              'a'+st->toContents->id,
                1971              st->toContents->rank,
                1972              stateNames[st->toContents->state]) ;
                1973     } else {
                1974       printf("null") ;
                1975     }
                1976     printf("]") ;
                1977     if (st->rank==st->toContents->rank) { // Don't dump too far...
                1978       dumpStackNext(st->next) ;
                1979     }
                1980   }
                1981 }
                1982 
                1983 void dumpStack(DoubleChainedBlock *st) {
                1984   if (st) {
                1985     printf("           ") ;
                1986     dumpStackPrev(st->prev) ;
                1987     printf(">>>[%02i ", st->rank) ;
                1988     if (st->toContents) {
                1989       printf("(%c: %02i %s)",
                1990              'a'+st->toContents->id,
                1991              st->toContents->rank,
                1992              stateNames[st->toContents->state]) ;
                1993     } else {
                1994       printf("null") ;
                1995     }
                1996     printf("]") ;
                1997     dumpStackNext(st->next) ;
                1998   }
                1999 }
                2000 
                2001 void dumpFileActionQueue() {
                2002   FileActionCell *inQueue = fileActionQueueHead ;
                2003   if (!inQueue) {
                2004     printf(" empty") ;
                2005   } else {
                2006     while (inQueue) {
                2007       if (inQueue->action==STORE) {
                2008         printf(" store (%c: %02i %s)",
                2009                'a'+inQueue->space->id,
                2010                inQueue->space->rank,
                2011                stateNames[inQueue->space->state]) ;
                2012       } else if (inQueue->action==RESTORE) {
                2013         printf(" restore %02i into (%c: %02i %s)",
                2014                inQueue->restoredRank,
                2015                'a'+inQueue->space->id,
                2016                inQueue->space->rank,
                2017                stateNames[inQueue->space->state]) ;
                2018       }
                2019       inQueue = inQueue->next ;
                2020     }
                2021   }
                2022 }
                2023 #endif
                2024 
                2025 void dumpContents(BlockContents* space) {
                2026   for (int i=0 ; i<ADSTACK_BLOCK_SIZE ; ++i) {
                2027     printf("%02x", (unsigned char)space->contents[i]) ;
                2028     if (i%10==9) printf(" ") ;
                2029     if (i%50==49) printf("\n") ;
                2030   }
                2031 }
                2032 
                2033 void dumpRepetitionLevels() {
                2034   RepetitionLevel *repetitionPoint = topRepetitionPoint ;
                2035   while (repetitionPoint) {
                2036     printf("  REPETITION LEVEL ACTIVE:%s BP:%s",
                2037            (repetitionPoint->active?"yes":"no"),
                2038            (repetitionPoint->hasBackPop?"yes":"no")) ;
                2039     if (repetitionPoint->hasBackPop)
                2040       {printf(" BP:") ; showLocation(repetitionPoint->backPopBlock, repetitionPoint->backPop) ;}
                2041     if (repetitionPoint->resumePointBlock)
                2042       {printf(" RP:") ; showLocation(repetitionPoint->resumePointBlock, repetitionPoint->resumePoint) ;}
                2043     if (repetitionPoint->freePushBlock)
                2044       {printf(" FP:") ; showLocation(repetitionPoint->freePushBlock, repetitionPoint->freePush) ;}
                2045     printf("\n") ;
                2046     repetitionPoint = repetitionPoint->previous ;
                2047     if (repetitionPoint) printf("  ...in") ;
                2048   }
                2049 }
                2050 
                2051 void showErrorContext() {
                2052   struct timespec ts;
                2053   clock_gettime(CLOCK_REALTIME, &ts);
                2054   printf("t%09i ERROR AT:", ts.tv_nsec) ; showLocation(curStack, tappos) ;
                2055 #ifdef ADSTACK_TRACE
                2056   printf(" STACK:") ; dumpStack(curStack) ; printf("\n") ;
                2057   printf("FILE ACTION QUEUE:\n") ;
                2058   dumpFileActionQueue() ; printf("\n") ;
                2059 #endif
                2060   printf("REPETITION LEVELS:\n") ;
                2061   dumpRepetitionLevels() ;
                2062 }
b4daa24319 Shre*2063 
                2064 void adStack_showPeakSize() {
                2065   printf("Peak stack size (%1li blocks): %1llu bytes\n",
feb7fa5d1e dngo*2066          maxBlocks, maxBlocks*((long int)ADSTACK_BLOCK_SIZE)) ;
b4daa24319 Shre*2067 }
                2068 
                2069 void adStack_showTotalTraffic() {
feb7fa5d1e dngo*2070   printf("Total push/pop traffic %1lu bytes\n", pushPopTraffic) ;
b4daa24319 Shre*2071 }
                2072 
                2073 void adStack_showStackSize(int label) {
                2074   printf(" %i--> <",label) ;
feb7fa5d1e dngo*2075   printf("%"PRId64"", adStack_getCurrentStackSize());
                2076 /*   showLocation(curStack, tappos) ; */
b4daa24319 Shre*2077   printf(">") ;
                2078 }
                2079 
                2080 void adStack_showStack(char *locationName) {
                2081   if (!curStack || (tappos==0 && !curStack->prev)) {
                2082     printf ("Stack at %s is empty\n", locationName) ;
                2083   } else {
                2084     printf ("Stack top at %s is %1i.%05i :\n", locationName, curStack->rank, tappos) ;
                2085     int bytesToShow = 20 ;
                2086     int blocksToShow = 3 ;
                2087     DoubleChainedBlock *inStack = curStack ;
                2088     int inPos = tappos ;
                2089     while (blocksToShow>0 && inStack) {
                2090       printf("  Block %d:", inStack->rank) ;
                2091       while (bytesToShow>0 && inPos>0) {
feb7fa5d1e dngo*2092         printf(" %02x", (unsigned char)inStack->toContents->contents[--inPos]) ;
b4daa24319 Shre*2093         --bytesToShow ;
                2094       }
                2095       if (inPos>0)
                2096         printf(" ...<%d more bytes>...", inPos) ;
                2097       printf(" |\n") ;
                2098       --blocksToShow ;
                2099       inStack = inStack->prev ;
feb7fa5d1e dngo*2100       inPos = ADSTACK_BLOCK_SIZE ;
b4daa24319 Shre*2101     }
                2102     if (inStack)
                2103       printf("  %d more blocks below\n", inStack->rank) ;
                2104   }
                2105   if (adbitibuf==0) {
                2106     printf("Bit buffer is empty\n") ;
                2107   } else {
                2108     printf("Bit buffer:%1i in %08x\n", adbitibuf, adbitbuf) ;
                2109   }
                2110   if (topRepetitionPoint) {
                2111     printf("Repetition levels:\n  ") ;
feb7fa5d1e dngo*2112     dumpRepetitionLevels() ;
b4daa24319 Shre*2113   }
                2114   printf("----------------\n") ;
                2115 }
                2116 
feb7fa5d1e dngo*2117 /******* Query if this stack was compiled with OpenMP ******/
                2118 
b4daa24319 Shre*2119 int stackIsThreadSafe() {
                2120   #ifdef _OPENMP
                2121     return 1 ;
                2122   #else
                2123     return 0 ;
                2124   #endif
                2125 }
                2126 
                2127 /****************** INTERFACE CALLED FROM FORTRAN *******************/
                2128 
                2129 void adstack_startrepeat_() {
                2130   adStack_startRepeat() ;
                2131 }
                2132 
                2133 void adstack_resetrepeat_() {
                2134   adStack_resetRepeat() ;
                2135 }
                2136 
                2137 void adstack_endrepeat_() {
                2138   adStack_endRepeat() ;
                2139 }
                2140 
                2141 void pushinteger4array_(int *ii, int *ll) {
                2142   pushInteger4Array(ii, *ll) ;
                2143 }
                2144 
                2145 void popinteger4array_(int *ii, int *ll) {
                2146   popInteger4Array(ii, *ll) ;
                2147 }
                2148 
                2149 void pushinteger8array_(long *ii, int *ll) {
                2150   pushInteger8Array(ii, *ll) ;
                2151 }
                2152 
                2153 void popinteger8array_(long *ii, int *ll) {
                2154   popInteger8Array(ii, *ll) ;
                2155 }
                2156 
                2157 void pushreal4array_(float *ii, int *ll) {
                2158   pushReal4Array(ii, *ll) ;
                2159 }
                2160 
                2161 void popreal4array_(float *ii, int *ll) {
                2162   popReal4Array(ii, *ll) ;
                2163 }
                2164 
                2165 void pushreal8array_(double *ii, int *ll) {
                2166   pushReal8Array(ii, *ll) ;
                2167 }
                2168 
                2169 void popreal8array_(double *ii, int *ll) {
                2170   popReal8Array(ii, *ll) ;
                2171 }
                2172 
feb7fa5d1e dngo*2173 void pushreal16array_(long double *ii, int *ll) {
                2174   pushReal16Array(ii, *ll) ;
                2175 }
                2176 
                2177 void popreal16array_(long double *ii, int *ll) {
                2178   popReal16Array(ii, *ll) ;
                2179 }
                2180 
b4daa24319 Shre*2181 void pushcomplex8array_(ccmplx *ii, int *ll) {
                2182   pushComplex8Array(ii, *ll) ;
                2183 }
                2184 
                2185 void popcomplex8array_(ccmplx *ii, int *ll) {
                2186   popComplex8Array(ii, *ll) ;
                2187 }
                2188 
                2189 void pushcomplex16array_(cdcmplx *ii, int *ll) {
                2190   pushComplex16Array((double complex *)ii, *ll) ;
                2191 }
                2192 
                2193 void popcomplex16array_(cdcmplx *ii, int *ll) {
                2194   popComplex16Array((double complex *)ii, *ll) ;
                2195 }
                2196 
                2197 void pushcharacterarray_(char *ii, int *ll) {
                2198   pushCharacterArray(ii, *ll) ;
                2199 }
                2200 
                2201 void popcharacterarray_(char *ii, int *ll) {
                2202   popCharacterArray(ii, *ll) ;
                2203 }
                2204 
                2205 void pushbooleanarray_(char *x, int *n) {
                2206   if (topRepetitionPoint) checkPushInReadOnly() ;
                2207   pushNArray(x,(*n*4)) ;
feb7fa5d1e dngo*2208 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*2209   pushPopTraffic += *n*4 ;
                2210 #endif
                2211 }
                2212 
                2213 void popbooleanarray_(char *x, int *n) {
                2214   popNArray(x,(*n*4)) ;
                2215   if (topRepetitionPoint) checkPopToReadOnly() ;
feb7fa5d1e dngo*2216 #ifdef ADSTACK_PROFILE
b4daa24319 Shre*2217   pushPopTraffic += *n*4 ;
                2218 #endif
                2219 }
                2220 
                2221 void pushcharacter_(char* val) {
                2222   pushCharacter(*val) ;
                2223 }
                2224 
                2225 void popcharacter_(char* val) {
                2226   popCharacter(val) ;
                2227 }
                2228 
                2229 void pushreal4_(float* val) {
                2230   pushReal4(*val) ;
                2231 }
                2232 
                2233 void popreal4_(float* val) {
                2234   popReal4(val) ;
                2235 }
                2236 
                2237 void pushreal8_(double* val) {
                2238   pushReal8(*val) ;
                2239 }
                2240 
                2241 void popreal8_(double* val) {
                2242   popReal8(val) ;
                2243 }
                2244 
feb7fa5d1e dngo*2245 void pushreal16_(long double *val) {
                2246   pushReal16(val) ;
                2247 }
                2248 
                2249 void popreal16_(long double *val) {
                2250   popReal16(val) ;
                2251 }
                2252 
b4daa24319 Shre*2253 void pushinteger4_(int* val) {
                2254   pushInteger4(*val) ;
                2255 }
                2256 
                2257 void popinteger4_(int* val) {
                2258   popInteger4(val) ;
                2259 }
                2260 
                2261 void pushinteger8_(long* val) {
                2262   pushInteger8(*val) ;
                2263 }
                2264 
                2265 void popinteger8_(long* val) {
                2266   popInteger8(val) ;
                2267 }
                2268 
                2269 void pushcomplex8_(ccmplx* val) {
                2270   pushComplex8(*val) ;
                2271 }
                2272 
                2273 void popcomplex8_(ccmplx* val) {
                2274   popComplex8(val) ;
                2275 }
                2276 
                2277 void pushcomplex16_(cdcmplx *val) {
                2278   pushComplex16(*((double complex *)val)) ;
                2279 }
                2280 
                2281 void popcomplex16_(cdcmplx* val) {
                2282   popComplex16((double complex *)val) ;
                2283 }
                2284 
                2285 void pushpointer4_(void** val) {
                2286   pushPointer4(*val) ;
                2287 }
                2288 
                2289 void poppointer4_(void** val) {
                2290   popPointer4(val) ;
                2291 }
                2292 
                2293 void pushpointer8_(void** val) {
                2294   pushPointer8(*val) ;
                2295 }
                2296 
                2297 void poppointer8_(void** val) {
                2298   popPointer8(val) ;
                2299 }
                2300 
                2301 void pushcontrol1b_(int* cc) {
                2302   pushControl1b(*cc) ;
                2303 }
                2304 
                2305 void popcontrol1b_(int *cc) {
                2306   popControl1b(cc) ;
                2307 }
                2308 
                2309 void pushcontrol2b_(int *cc) {
                2310   pushControl2b(*cc) ;
                2311 }
                2312 
                2313 void popcontrol2b_(int *cc) {
                2314   popControl2b(cc) ;
                2315 }
                2316 
                2317 void pushcontrol3b_(int *cc) {
                2318   pushControl3b(*cc) ;
                2319 }
                2320 
                2321 void popcontrol3b_(int *cc) {
                2322   popControl3b(cc) ;
                2323 }
                2324 
                2325 void pushcontrol4b_(int *cc) {
                2326   pushControl4b(*cc) ;
                2327 }
                2328 
                2329 void popcontrol4b_(int *cc) {
                2330   popControl4b(cc) ;
                2331 }
                2332 
                2333 void pushcontrol5b_(int *cc) {
                2334   pushControl5b(*cc) ;
                2335 }
                2336 
                2337 void popcontrol5b_(int *cc) {
                2338   popControl5b(cc) ;
                2339 }
                2340 
                2341 void pushcontrol6b_(int *cc) {
                2342   pushControl6b(*cc) ;
                2343 }
                2344 
                2345 void popcontrol6b_(int *cc) {
                2346   popControl6b(cc) ;
                2347 }
                2348 
                2349 void pushcontrol7b_(int *cc) {
                2350   pushControl7b(*cc) ;
                2351 }
                2352 
                2353 void popcontrol7b_(int *cc) {
                2354   popControl7b(cc) ;
                2355 }
                2356 
                2357 void pushcontrol8b_(int *cc) {
                2358   pushControl8b(*cc) ;
                2359 }
                2360 
                2361 void popcontrol8b_(int *cc) {
                2362   popControl8b(cc) ;
                2363 }
                2364 
feb7fa5d1e dngo*2365 void pushboolean_(int *x) {
                2366   pushBoolean(*x) ;
                2367 }
                2368 
                2369 void popboolean_(int *x) {
                2370   popBoolean(x) ;
                2371 }
                2372 
b4daa24319 Shre*2373 void adstack_showpeaksize_() {
                2374   adStack_showPeakSize() ;
                2375 }
                2376 
                2377 void adstack_showtotaltraffic_() {
                2378   adStack_showTotalTraffic() ;
                2379 }
                2380 
                2381 void adstack_showstacksize_(int *label) {
                2382   adStack_showStackSize(*label) ;
                2383 }
                2384 
                2385 void adstack_showstack_(char *locationName) {
                2386   adStack_showStack(locationName) ;
                2387 }
                2388 
feb7fa5d1e dngo*2389 int stackisthreadsafe_() {
                2390   return stackIsThreadSafe() ;
b4daa24319 Shre*2391 }
                2392 
feb7fa5d1e dngo*2393 void showerrorcontext_() {
                2394   showErrorContext() ;
                2395   fflush(stdout) ;
b4daa24319 Shre*2396 }
                2397 
feb7fa5d1e dngo*2398 int locstrb_() {return (curStack ? curStack->rank : 0) ;}
                2399 int locstro_() {return tappos;}