10f453b92SJed Brown #include <petscsys.h> 20f453b92SJed Brown 3137cf7b6SJed Brown struct _PetscSegBufferLink { 4137cf7b6SJed Brown struct _PetscSegBufferLink *tail; 513e3f751SJed Brown size_t alloc; 613e3f751SJed Brown size_t used; 713e3f751SJed Brown size_t tailused; 89371c9d4SSatish Balay union 99371c9d4SSatish Balay { /* Dummy types to ensure alignment */ 100f453b92SJed Brown PetscReal dummy_real; 110f453b92SJed Brown PetscInt dummy_int; 12137cf7b6SJed Brown char array[1]; /* This array is over-allocated for the size of the link */ 130f453b92SJed Brown } u; 140f453b92SJed Brown }; 150f453b92SJed Brown 16137cf7b6SJed Brown /* Segmented (extendable) array implementation */ 17137cf7b6SJed Brown struct _n_PetscSegBuffer { 18137cf7b6SJed Brown struct _PetscSegBufferLink *head; 1913e3f751SJed Brown size_t unitbytes; 20137cf7b6SJed Brown }; 21137cf7b6SJed Brown 22d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSegBufferAlloc_Private(PetscSegBuffer seg, size_t count) 23d71ae5a4SJacob Faibussowitsch { 2413e3f751SJed Brown size_t alloc; 25137cf7b6SJed Brown struct _PetscSegBufferLink *newlink, *s; 260f453b92SJed Brown 270f453b92SJed Brown PetscFunctionBegin; 28137cf7b6SJed Brown s = seg->head; 290f453b92SJed Brown /* Grow at least fast enough to hold next item, like Fibonacci otherwise (up to 1MB chunks) */ 30137cf7b6SJed Brown alloc = PetscMax(s->used + count, PetscMin(1000000 / seg->unitbytes + 1, s->alloc + s->tailused)); 319566063dSJacob Faibussowitsch PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + alloc * seg->unitbytes, &newlink)); 329566063dSJacob Faibussowitsch PetscCall(PetscMemzero(newlink, offsetof(struct _PetscSegBufferLink, u))); 330f453b92SJed Brown 34137cf7b6SJed Brown newlink->tailused = s->used + s->tailused; 35137cf7b6SJed Brown newlink->tail = s; 36137cf7b6SJed Brown newlink->alloc = alloc; 37137cf7b6SJed Brown seg->head = newlink; 38*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 390f453b92SJed Brown } 400f453b92SJed Brown 410f453b92SJed Brown /*@C 42811af0c4SBarry Smith PetscSegBufferCreate - create a segmented buffer 430f453b92SJed Brown 440f453b92SJed Brown Not Collective 450f453b92SJed Brown 464165533cSJose E. Roman Input Parameters: 470f453b92SJed Brown + unitbytes - number of bytes that each entry will contain 480f453b92SJed Brown - expected - expected/typical number of entries 490f453b92SJed Brown 504165533cSJose E. Roman Output Parameter: 510f453b92SJed Brown . seg - segmented buffer object 520f453b92SJed Brown 530f453b92SJed Brown Level: developer 540f453b92SJed Brown 55db781477SPatrick Sanan .seealso: `PetscSegBufferGet()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()` 560f453b92SJed Brown @*/ 57d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferCreate(size_t unitbytes, size_t expected, PetscSegBuffer *seg) 58d71ae5a4SJacob Faibussowitsch { 59137cf7b6SJed Brown struct _PetscSegBufferLink *head; 600f453b92SJed Brown 610f453b92SJed Brown PetscFunctionBegin; 629566063dSJacob Faibussowitsch PetscCall(PetscNew(seg)); 639566063dSJacob Faibussowitsch PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + expected * unitbytes, &head)); 649566063dSJacob Faibussowitsch PetscCall(PetscMemzero(head, offsetof(struct _PetscSegBufferLink, u))); 650f453b92SJed Brown 66137cf7b6SJed Brown head->alloc = expected; 670f453b92SJed Brown (*seg)->unitbytes = unitbytes; 68137cf7b6SJed Brown (*seg)->head = head; 69*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 700f453b92SJed Brown } 710f453b92SJed Brown 720f453b92SJed Brown /*@C 730f453b92SJed Brown PetscSegBufferGet - get new buffer space from a segmented buffer 740f453b92SJed Brown 750f453b92SJed Brown Not Collective 760f453b92SJed Brown 774165533cSJose E. Roman Input Parameters: 780f453b92SJed Brown + seg - address of segmented buffer 790f453b92SJed Brown - count - number of entries needed 800f453b92SJed Brown 814165533cSJose E. Roman Output Parameter: 820f453b92SJed Brown . buf - address of new buffer for contiguous data 830f453b92SJed Brown 840f453b92SJed Brown Level: developer 850f453b92SJed Brown 86db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()` 870f453b92SJed Brown @*/ 88d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg, size_t count, void *buf) 89d71ae5a4SJacob Faibussowitsch { 90137cf7b6SJed Brown struct _PetscSegBufferLink *s; 910f453b92SJed Brown 920f453b92SJed Brown PetscFunctionBegin; 93137cf7b6SJed Brown s = seg->head; 949566063dSJacob Faibussowitsch if (PetscUnlikely(s->used + count > s->alloc)) PetscCall(PetscSegBufferAlloc_Private(seg, count)); 95137cf7b6SJed Brown s = seg->head; 96137cf7b6SJed Brown *(char **)buf = &s->u.array[s->used * seg->unitbytes]; 970f453b92SJed Brown s->used += count; 98*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 990f453b92SJed Brown } 1000f453b92SJed Brown 1010f453b92SJed Brown /*@C 1020f453b92SJed Brown PetscSegBufferDestroy - destroy segmented buffer 1030f453b92SJed Brown 1040f453b92SJed Brown Not Collective 1050f453b92SJed Brown 1064165533cSJose E. Roman Input Parameter: 1070f453b92SJed Brown . seg - address of segmented buffer object 1080f453b92SJed Brown 1090f453b92SJed Brown Level: developer 1100f453b92SJed Brown 111db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()` 1120f453b92SJed Brown @*/ 113d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg) 114d71ae5a4SJacob Faibussowitsch { 115137cf7b6SJed Brown struct _PetscSegBufferLink *s; 1160f453b92SJed Brown 1170f453b92SJed Brown PetscFunctionBegin; 118*3ba16761SJacob Faibussowitsch if (!*seg) PetscFunctionReturn(PETSC_SUCCESS); 119137cf7b6SJed Brown for (s = (*seg)->head; s;) { 120137cf7b6SJed Brown struct _PetscSegBufferLink *tail = s->tail; 1219566063dSJacob Faibussowitsch PetscCall(PetscFree(s)); 1220f453b92SJed Brown s = tail; 1230f453b92SJed Brown } 1249566063dSJacob Faibussowitsch PetscCall(PetscFree(*seg)); 125*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1260f453b92SJed Brown } 1270f453b92SJed Brown 1280f453b92SJed Brown /*@C 12947452e7bSJed Brown PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer 13047452e7bSJed Brown 13147452e7bSJed Brown Not Collective 13247452e7bSJed Brown 1334165533cSJose E. Roman Input Parameters: 13447452e7bSJed Brown + seg - segmented buffer 13547452e7bSJed Brown - contig - allocated buffer to hold contiguous data 13647452e7bSJed Brown 13747452e7bSJed Brown Level: developer 13847452e7bSJed Brown 139db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractInPlace()` 14047452e7bSJed Brown @*/ 141d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg, void *contig) 142d71ae5a4SJacob Faibussowitsch { 14313e3f751SJed Brown size_t unitbytes; 144137cf7b6SJed Brown struct _PetscSegBufferLink *s, *t; 14547452e7bSJed Brown char *ptr; 14647452e7bSJed Brown 14747452e7bSJed Brown PetscFunctionBegin; 148137cf7b6SJed Brown unitbytes = seg->unitbytes; 149137cf7b6SJed Brown s = seg->head; 15047452e7bSJed Brown ptr = ((char *)contig) + s->tailused * unitbytes; 1519566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, s->u.array, s->used * unitbytes)); 15247452e7bSJed Brown for (t = s->tail; t;) { 153137cf7b6SJed Brown struct _PetscSegBufferLink *tail = t->tail; 15447452e7bSJed Brown ptr -= t->used * unitbytes; 1559566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, t->u.array, t->used * unitbytes)); 1569566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 15747452e7bSJed Brown t = tail; 15847452e7bSJed Brown } 15908401ef6SPierre Jolivet PetscCheck(ptr == contig, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Tail count does not match"); 16047452e7bSJed Brown s->used = 0; 16147452e7bSJed Brown s->tailused = 0; 16247452e7bSJed Brown s->tail = NULL; 163*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16447452e7bSJed Brown } 16547452e7bSJed Brown 16647452e7bSJed Brown /*@C 16747452e7bSJed Brown PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer 1680f453b92SJed Brown 1690f453b92SJed Brown Not Collective 1700f453b92SJed Brown 1714165533cSJose E. Roman Input Parameter: 1720f453b92SJed Brown . seg - segmented buffer 1730f453b92SJed Brown 1744165533cSJose E. Roman Output Parameter: 175811af0c4SBarry Smith . contiguous - address of new array containing contiguous data, caller frees with `PetscFree()` 1760f453b92SJed Brown 1770f453b92SJed Brown Level: developer 1780f453b92SJed Brown 179811af0c4SBarry Smith Developer Note: 180811af0c4SBarry Smith 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done 18147452e7bSJed Brown 182db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()` 1830f453b92SJed Brown @*/ 184d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg, void *contiguous) 185d71ae5a4SJacob Faibussowitsch { 186137cf7b6SJed Brown struct _PetscSegBufferLink *s; 18747452e7bSJed Brown void *contig; 1880f453b92SJed Brown 1890f453b92SJed Brown PetscFunctionBegin; 190137cf7b6SJed Brown s = seg->head; 1910f453b92SJed Brown 1929566063dSJacob Faibussowitsch PetscCall(PetscMalloc((s->used + s->tailused) * seg->unitbytes, &contig)); 1939566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, contig)); 19447452e7bSJed Brown *(void **)contiguous = contig; 195*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1960f453b92SJed Brown } 19747452e7bSJed Brown 19847452e7bSJed Brown /*@C 19947452e7bSJed Brown PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse 20047452e7bSJed Brown 20101d09641SJed Brown Not Collective 20247452e7bSJed Brown 2034165533cSJose E. Roman Input Parameter: 20447452e7bSJed Brown . seg - segmented buffer object 20547452e7bSJed Brown 2064165533cSJose E. Roman Output Parameter: 207d2b3fd65SBarry Smith . contig - address of pointer to contiguous memory, may be NULL 20847452e7bSJed Brown 20947452e7bSJed Brown Level: developer 21047452e7bSJed Brown 211db781477SPatrick Sanan .seealso: `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()` 21247452e7bSJed Brown @*/ 213d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg, void *contig) 214d71ae5a4SJacob Faibussowitsch { 215137cf7b6SJed Brown struct _PetscSegBufferLink *head; 21647452e7bSJed Brown 21747452e7bSJed Brown PetscFunctionBegin; 218137cf7b6SJed Brown head = seg->head; 219137cf7b6SJed Brown if (PetscUnlikely(head->tail)) { 220137cf7b6SJed Brown PetscSegBuffer newseg; 22147452e7bSJed Brown 2229566063dSJacob Faibussowitsch PetscCall(PetscSegBufferCreate(seg->unitbytes, head->used + head->tailused, &newseg)); 2239566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, newseg->head->u.array)); 224137cf7b6SJed Brown seg->head = newseg->head; 225137cf7b6SJed Brown newseg->head = head; 2269566063dSJacob Faibussowitsch PetscCall(PetscSegBufferDestroy(&newseg)); 227137cf7b6SJed Brown head = seg->head; 22847452e7bSJed Brown } 229d2b3fd65SBarry Smith if (contig) *(char **)contig = head->u.array; 230137cf7b6SJed Brown head->used = 0; 231*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2320f453b92SJed Brown } 23301d09641SJed Brown 23401d09641SJed Brown /*@C 23501d09641SJed Brown PetscSegBufferGetSize - get currently used size of segmented buffer 23601d09641SJed Brown 23701d09641SJed Brown Not Collective 23801d09641SJed Brown 2394165533cSJose E. Roman Input Parameter: 24001d09641SJed Brown . seg - segmented buffer object 24101d09641SJed Brown 2424165533cSJose E. Roman Output Parameter: 24301d09641SJed Brown . usedsize - number of used units 24401d09641SJed Brown 24501d09641SJed Brown Level: developer 24601d09641SJed Brown 247db781477SPatrick Sanan .seealso: `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferCreate()`, `PetscSegBufferGet()` 24801d09641SJed Brown @*/ 249d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg, size_t *usedsize) 250d71ae5a4SJacob Faibussowitsch { 25101d09641SJed Brown PetscFunctionBegin; 252137cf7b6SJed Brown *usedsize = seg->head->tailused + seg->head->used; 253*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25401d09641SJed Brown } 25501d09641SJed Brown 25601d09641SJed Brown /*@C 257811af0c4SBarry Smith PetscSegBufferUnuse - return some unused entries obtained with an overzealous `PetscSegBufferGet()` 25801d09641SJed Brown 25901d09641SJed Brown Not Collective 26001d09641SJed Brown 2614165533cSJose E. Roman Input Parameters: 26201d09641SJed Brown + seg - segmented buffer object 26301d09641SJed Brown - unused - number of unused units 26401d09641SJed Brown 26501d09641SJed Brown Level: developer 26601d09641SJed Brown 267db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()` 26801d09641SJed Brown @*/ 269d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg, size_t unused) 270d71ae5a4SJacob Faibussowitsch { 271137cf7b6SJed Brown struct _PetscSegBufferLink *head; 27201d09641SJed Brown 27301d09641SJed Brown PetscFunctionBegin; 274137cf7b6SJed Brown head = seg->head; 27508401ef6SPierre Jolivet PetscCheck(head->used >= unused, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to return more unused entries (%zu) than previously gotten (%zu)", unused, head->used); 276137cf7b6SJed Brown head->used -= unused; 277*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27801d09641SJed Brown } 279