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; 383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 390f453b92SJed Brown } 400f453b92SJed Brown 410f453b92SJed Brown /*@C 42811af0c4SBarry Smith PetscSegBufferCreate - create a segmented buffer 430f453b92SJed Brown 44*cc4c1da9SBarry Smith Not Collective, No Fortran Support 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: 51667f096bSBarry Smith . seg - `PetscSegBuffer` object 520f453b92SJed Brown 530f453b92SJed Brown Level: developer 540f453b92SJed Brown 55667f096bSBarry Smith .seealso: `PetscSegBufferGet()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()`, 56667f096bSBarry Smith `PetscSegBuffer` 570f453b92SJed Brown @*/ 58d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferCreate(size_t unitbytes, size_t expected, PetscSegBuffer *seg) 59d71ae5a4SJacob Faibussowitsch { 60137cf7b6SJed Brown struct _PetscSegBufferLink *head; 610f453b92SJed Brown 620f453b92SJed Brown PetscFunctionBegin; 639566063dSJacob Faibussowitsch PetscCall(PetscNew(seg)); 649566063dSJacob Faibussowitsch PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + expected * unitbytes, &head)); 659566063dSJacob Faibussowitsch PetscCall(PetscMemzero(head, offsetof(struct _PetscSegBufferLink, u))); 660f453b92SJed Brown 67137cf7b6SJed Brown head->alloc = expected; 680f453b92SJed Brown (*seg)->unitbytes = unitbytes; 69137cf7b6SJed Brown (*seg)->head = head; 703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 710f453b92SJed Brown } 720f453b92SJed Brown 730f453b92SJed Brown /*@C 740f453b92SJed Brown PetscSegBufferGet - get new buffer space from a segmented buffer 750f453b92SJed Brown 76*cc4c1da9SBarry Smith Not Collective, No Fortran Support 770f453b92SJed Brown 784165533cSJose E. Roman Input Parameters: 79667f096bSBarry Smith + seg - `PetscSegBuffer` buffer 800f453b92SJed Brown - count - number of entries needed 810f453b92SJed Brown 824165533cSJose E. Roman Output Parameter: 830f453b92SJed Brown . buf - address of new buffer for contiguous data 840f453b92SJed Brown 850f453b92SJed Brown Level: developer 860f453b92SJed Brown 87667f096bSBarry Smith .seealso: `PetscSegBufferCreate()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()`, 88667f096bSBarry Smith `PetscSegBuffer` 890f453b92SJed Brown @*/ 90d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg, size_t count, void *buf) 91d71ae5a4SJacob Faibussowitsch { 92137cf7b6SJed Brown struct _PetscSegBufferLink *s; 930f453b92SJed Brown 940f453b92SJed Brown PetscFunctionBegin; 95137cf7b6SJed Brown s = seg->head; 969566063dSJacob Faibussowitsch if (PetscUnlikely(s->used + count > s->alloc)) PetscCall(PetscSegBufferAlloc_Private(seg, count)); 97137cf7b6SJed Brown s = seg->head; 98137cf7b6SJed Brown *(char **)buf = &s->u.array[s->used * seg->unitbytes]; 990f453b92SJed Brown s->used += count; 1003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1010f453b92SJed Brown } 1020f453b92SJed Brown 1030f453b92SJed Brown /*@C 1040f453b92SJed Brown PetscSegBufferDestroy - destroy segmented buffer 1050f453b92SJed Brown 106*cc4c1da9SBarry Smith Not Collective, No Fortran Support 1070f453b92SJed Brown 1084165533cSJose E. Roman Input Parameter: 1090f453b92SJed Brown . seg - address of segmented buffer object 1100f453b92SJed Brown 1110f453b92SJed Brown Level: developer 1120f453b92SJed Brown 113667f096bSBarry Smith .seealso: `PetscSegBuffer`, `PetscSegBufferCreate()` 1140f453b92SJed Brown @*/ 115d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg) 116d71ae5a4SJacob Faibussowitsch { 117137cf7b6SJed Brown struct _PetscSegBufferLink *s; 1180f453b92SJed Brown 1190f453b92SJed Brown PetscFunctionBegin; 1203ba16761SJacob Faibussowitsch if (!*seg) PetscFunctionReturn(PETSC_SUCCESS); 121137cf7b6SJed Brown for (s = (*seg)->head; s;) { 122137cf7b6SJed Brown struct _PetscSegBufferLink *tail = s->tail; 1239566063dSJacob Faibussowitsch PetscCall(PetscFree(s)); 1240f453b92SJed Brown s = tail; 1250f453b92SJed Brown } 1269566063dSJacob Faibussowitsch PetscCall(PetscFree(*seg)); 1273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1280f453b92SJed Brown } 1290f453b92SJed Brown 1300f453b92SJed Brown /*@C 13147452e7bSJed Brown PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer 13247452e7bSJed Brown 133*cc4c1da9SBarry Smith Not Collective, No Fortran Support 13447452e7bSJed Brown 1354165533cSJose E. Roman Input Parameters: 13647452e7bSJed Brown + seg - segmented buffer 13747452e7bSJed Brown - contig - allocated buffer to hold contiguous data 13847452e7bSJed Brown 13947452e7bSJed Brown Level: developer 14047452e7bSJed Brown 141667f096bSBarry Smith .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractInPlace()`, 142667f096bSBarry Smith `PetscSegBuffer` 14347452e7bSJed Brown @*/ 144d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg, void *contig) 145d71ae5a4SJacob Faibussowitsch { 14613e3f751SJed Brown size_t unitbytes; 147137cf7b6SJed Brown struct _PetscSegBufferLink *s, *t; 14847452e7bSJed Brown char *ptr; 14947452e7bSJed Brown 15047452e7bSJed Brown PetscFunctionBegin; 151137cf7b6SJed Brown unitbytes = seg->unitbytes; 152137cf7b6SJed Brown s = seg->head; 1538e3a54c0SPierre Jolivet ptr = PetscSafePointerPlusOffset((char *)contig, s->tailused * unitbytes); 1549566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, s->u.array, s->used * unitbytes)); 15547452e7bSJed Brown for (t = s->tail; t;) { 156137cf7b6SJed Brown struct _PetscSegBufferLink *tail = t->tail; 15747452e7bSJed Brown ptr -= t->used * unitbytes; 1589566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, t->u.array, t->used * unitbytes)); 1599566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 16047452e7bSJed Brown t = tail; 16147452e7bSJed Brown } 16208401ef6SPierre Jolivet PetscCheck(ptr == contig, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Tail count does not match"); 16347452e7bSJed Brown s->used = 0; 16447452e7bSJed Brown s->tailused = 0; 16547452e7bSJed Brown s->tail = NULL; 1663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16747452e7bSJed Brown } 16847452e7bSJed Brown 16947452e7bSJed Brown /*@C 17047452e7bSJed Brown PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer 1710f453b92SJed Brown 172*cc4c1da9SBarry Smith Not Collective, No Fortran Support 1730f453b92SJed Brown 1744165533cSJose E. Roman Input Parameter: 175667f096bSBarry Smith . seg - `PetscSegBuffer` buffer 1760f453b92SJed Brown 1774165533cSJose E. Roman Output Parameter: 178811af0c4SBarry Smith . contiguous - address of new array containing contiguous data, caller frees with `PetscFree()` 1790f453b92SJed Brown 1800f453b92SJed Brown Level: developer 1810f453b92SJed Brown 182aec76313SJacob Faibussowitsch Developer Notes: 183811af0c4SBarry Smith 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done 18447452e7bSJed Brown 185667f096bSBarry Smith .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, 186667f096bSBarry Smith `PetscSegBuffer` 1870f453b92SJed Brown @*/ 188d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg, void *contiguous) 189d71ae5a4SJacob Faibussowitsch { 190137cf7b6SJed Brown struct _PetscSegBufferLink *s; 19147452e7bSJed Brown void *contig; 1920f453b92SJed Brown 1930f453b92SJed Brown PetscFunctionBegin; 194137cf7b6SJed Brown s = seg->head; 1950f453b92SJed Brown 1969566063dSJacob Faibussowitsch PetscCall(PetscMalloc((s->used + s->tailused) * seg->unitbytes, &contig)); 1979566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, contig)); 19847452e7bSJed Brown *(void **)contiguous = contig; 1993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2000f453b92SJed Brown } 20147452e7bSJed Brown 20247452e7bSJed Brown /*@C 20347452e7bSJed Brown PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse 20447452e7bSJed Brown 205*cc4c1da9SBarry Smith Not Collective, No Fortran Support 20647452e7bSJed Brown 2074165533cSJose E. Roman Input Parameter: 208667f096bSBarry Smith . seg - `PetscSegBuffer` object 20947452e7bSJed Brown 2104165533cSJose E. Roman Output Parameter: 211667f096bSBarry Smith . contig - address of pointer to contiguous memory, may be `NULL` 21247452e7bSJed Brown 21347452e7bSJed Brown Level: developer 21447452e7bSJed Brown 215667f096bSBarry Smith .seealso: `PetscSegBuffer`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()` 21647452e7bSJed Brown @*/ 217d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg, void *contig) 218d71ae5a4SJacob Faibussowitsch { 219137cf7b6SJed Brown struct _PetscSegBufferLink *head; 22047452e7bSJed Brown 22147452e7bSJed Brown PetscFunctionBegin; 222137cf7b6SJed Brown head = seg->head; 223137cf7b6SJed Brown if (PetscUnlikely(head->tail)) { 224137cf7b6SJed Brown PetscSegBuffer newseg; 22547452e7bSJed Brown 2269566063dSJacob Faibussowitsch PetscCall(PetscSegBufferCreate(seg->unitbytes, head->used + head->tailused, &newseg)); 2279566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, newseg->head->u.array)); 228137cf7b6SJed Brown seg->head = newseg->head; 229137cf7b6SJed Brown newseg->head = head; 2309566063dSJacob Faibussowitsch PetscCall(PetscSegBufferDestroy(&newseg)); 231137cf7b6SJed Brown head = seg->head; 23247452e7bSJed Brown } 233d2b3fd65SBarry Smith if (contig) *(char **)contig = head->u.array; 234137cf7b6SJed Brown head->used = 0; 2353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2360f453b92SJed Brown } 23701d09641SJed Brown 23801d09641SJed Brown /*@C 239667f096bSBarry Smith PetscSegBufferGetSize - get currently used size of a `PetscSegBuffer` 24001d09641SJed Brown 241*cc4c1da9SBarry Smith Not Collective, No Fortran Support 24201d09641SJed Brown 2434165533cSJose E. Roman Input Parameter: 244667f096bSBarry Smith . seg - `PetscSegBuffer` object 24501d09641SJed Brown 2464165533cSJose E. Roman Output Parameter: 24701d09641SJed Brown . usedsize - number of used units 24801d09641SJed Brown 24901d09641SJed Brown Level: developer 25001d09641SJed Brown 251667f096bSBarry Smith .seealso: `PetscSegBuffer`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferCreate()`, `PetscSegBufferGet()` 25201d09641SJed Brown @*/ 253d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg, size_t *usedsize) 254d71ae5a4SJacob Faibussowitsch { 25501d09641SJed Brown PetscFunctionBegin; 256137cf7b6SJed Brown *usedsize = seg->head->tailused + seg->head->used; 2573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25801d09641SJed Brown } 25901d09641SJed Brown 26001d09641SJed Brown /*@C 261811af0c4SBarry Smith PetscSegBufferUnuse - return some unused entries obtained with an overzealous `PetscSegBufferGet()` 26201d09641SJed Brown 263*cc4c1da9SBarry Smith Not Collective, No Fortran Support 26401d09641SJed Brown 2654165533cSJose E. Roman Input Parameters: 266667f096bSBarry Smith + seg - `PetscSegBuffer` object 26701d09641SJed Brown - unused - number of unused units 26801d09641SJed Brown 26901d09641SJed Brown Level: developer 27001d09641SJed Brown 271667f096bSBarry Smith .seealso: `PetscSegBuffer`, `PetscSegBufferCreate()`, `PetscSegBufferGet()` 27201d09641SJed Brown @*/ 273d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg, size_t unused) 274d71ae5a4SJacob Faibussowitsch { 275137cf7b6SJed Brown struct _PetscSegBufferLink *head; 27601d09641SJed Brown 27701d09641SJed Brown PetscFunctionBegin; 278137cf7b6SJed Brown head = seg->head; 27908401ef6SPierre 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); 280137cf7b6SJed Brown head->used -= unused; 2813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 28201d09641SJed Brown } 283