-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make disjoint pool a C structure #898
base: main
Are you sure you want to change the base?
Conversation
97807f1
to
3521be5
Compare
17d00a2
to
9b22721
Compare
cdad0f1
to
4a8935a
Compare
5764115
to
e8bc871
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...
README.md
Outdated
@@ -258,10 +257,6 @@ To enable this feature, the `UMF_BUILD_SHARED_LIBRARY` option needs to be turned | |||
|
|||
TODO: Add a description |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you pls add some description here?
and also mention that it is (part of libumf)
now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about all debug_logs. Imho there are litte too much logs for production code, so maybe we should try to reduce them to maximum 1-2 logs per API call.
if (mutex_internal->lock.RecursionCount > 1) { | ||
LeaveCriticalSection(&mutex_internal->lock); | ||
if (mutex->lock.RecursionCount > 1) { | ||
LeaveCriticalSection(&mutex->lock); | ||
/* deadlock detected */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a critical error and it should abort program
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what change do you suggest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As i said Abort(). It's critical issue in our library, it should never happen.
Or add error handling to all mutex_locks, but i prefer first one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pool/pool_disjoint.c
Outdated
// Temporary solution for disabling memory poisoning. This is needed because | ||
// AddressSanitizer does not support memory poisoning for GPU allocations. | ||
// More info: https://github.com/oneapi-src/unified-memory-framework/issues/634 | ||
#ifndef POISON_MEMORY | ||
#define POISON_MEMORY 0 | ||
#endif | ||
|
||
static void annotate_memory_inaccessible(void *ptr, size_t size) { | ||
(void)ptr; | ||
(void)size; | ||
#if (POISON_MEMORY != 0) | ||
utils_annotate_memory_inaccessible(ptr, size); | ||
#endif | ||
} | ||
|
||
static void annotate_memory_undefined(void *ptr, size_t size) { | ||
(void)ptr; | ||
(void)size; | ||
#if (POISON_MEMORY != 0) | ||
utils_annotate_memory_undefined(ptr, size); | ||
#endif | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Temporary solution for disabling memory poisoning. This is needed because | |
// AddressSanitizer does not support memory poisoning for GPU allocations. | |
// More info: https://github.com/oneapi-src/unified-memory-framework/issues/634 | |
#ifndef POISON_MEMORY | |
#define POISON_MEMORY 0 | |
#endif | |
static void annotate_memory_inaccessible(void *ptr, size_t size) { | |
(void)ptr; | |
(void)size; | |
#if (POISON_MEMORY != 0) | |
utils_annotate_memory_inaccessible(ptr, size); | |
#endif | |
} | |
static void annotate_memory_undefined(void *ptr, size_t size) { | |
(void)ptr; | |
(void)size; | |
#if (POISON_MEMORY != 0) | |
utils_annotate_memory_undefined(ptr, size); | |
#endif | |
} | |
// Temporary solution for disabling memory poisoning. This is needed because | |
// AddressSanitizer does not support memory poisoning for GPU allocations. | |
// More info: https://github.com/oneapi-src/unified-memory-framework/issues/634 | |
#ifndef POISON_MEMORY | |
#undef __SANITIZE_ADDRESS__ | |
#endif | |
#include "utils_sanitizers.h" | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pool/pool_disjoint.c
Outdated
slab->bucket = bucket; | ||
|
||
slab->iter = | ||
(slab_list_item_t *)umf_ba_global_alloc(sizeof(slab_list_item_t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer c++. Cast is not needed
sizeof(slab->iter )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pool/pool_disjoint.c
Outdated
slab_t *create_slab(bucket_t *bucket, bool full_size) { | ||
assert(bucket); | ||
|
||
slab_t *slab = umf_ba_global_alloc(sizeof(slab_t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sizeof(*slab)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, no, no. * slab looks like dereferencing an pointer which is invalid at the time I pass it to sizeof(). I understand this will compile but let's say I got a function that allocates mem and returns void * and I don't know the "name" of the results pointer - what should I then pass to sizeof? passing variable name instead of type in such simple cases looks strange and makes things more complex to understand
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If i cannot convince you let me show some references (by searching for them i did not found single one preferring sizeof(type) instead of sizeof(variable)):
1.
The preferred form for passing a size of a struct is the following:
p = kmalloc(sizeof(*p), ...);
The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not.
https://www.kernel.org/doc/html/v4.10/process/coding-style.html#allocating-memory
I perfer sizeof(variable) over sizeof(type). Consider:
int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));vs.
int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));In the first case, it's easy to verify that the right sizes are being passed to memset. In the second case, you need to constantly review top and bottom sections to make sure you are consistent.
https://softwareengineering.stackexchange.com/questions/201104/sizeof-style-sizeoftype-or-sizeof-variable
Prefer sizeof(varname) to sizeof(type).
Use sizeof(varname) when you take the size of a particular variable. sizeof(varname) will update appropriately if someone changes the variable type either now or later.
https://google.github.io/styleguide/cppguide.html#sizeof
IMO a = malloc(sizeof(int)); is poor, and worse than a = (int *)malloc(sizeof(int));, because you cannot tell just from looking at this line whether or not it is correct.
a = malloc(sizeof(*a)); is obviously correct.
https://www.reddit.com/r/C_Programming/comments/6e008m/sizeof_type_vs_sizeof_variable/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
slab->chunks = umf_ba_global_alloc(sizeof(bool) * slab->num_chunks); | ||
if (slab->chunks == NULL) { | ||
LOG_ERR("allocation of slab chunks failed!"); | ||
umf_ba_global_free(slab->iter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use goto to handle errors
src/pool/pool_disjoint.c
Outdated
#ifndef NDEBUG | ||
// debug check | ||
bucket_t *bucket = pool->buckets[calculated_idx]; | ||
assert(bucket->size >= size); | ||
(void)bucket; | ||
|
||
if (calculated_idx > 0) { | ||
bucket_t *bucket_prev = pool->buckets[calculated_idx - 1]; | ||
assert(bucket_prev->size < size); | ||
(void)bucket_prev; | ||
} | ||
#endif // NDEBUG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If buckets are created on pool creation, do we need to check their sizes and order each time that we are looking for correct one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
void bucket_print_stats(bucket_t *bucket, bool *title_printed, | ||
const char *label) { | ||
if (bucket->alloc_count) { | ||
if (!*title_printed) { | ||
LOG_DEBUG("\"%s\" pool memory statistics", label); | ||
LOG_DEBUG("%14s %12s %12s %18s %20s %21s", "Bucket Size", "Allocs", | ||
"Frees", "Allocs from Pool", "Peak Slabs in Use", | ||
"Peak Slabs in Pool"); | ||
*title_printed = true; | ||
} | ||
LOG_DEBUG("%14zu %12zu %12zu %18zu %20zu %21zu", bucket->size, | ||
bucket->alloc_count, bucket->free_count, | ||
bucket->alloc_pool_count, bucket->max_slabs_in_use, | ||
bucket->max_slabs_in_pool); | ||
} | ||
} | ||
|
||
void disjoint_pool_print_stats(disjoint_pool_t *pool, bool *title_printed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of bool *title_printed, create function print_title and just print once, without extra pointer argument passed to all functions.
|
||
disjoint_pool_print_stats(hPool, &title_printed, &high_bucket_size, | ||
&high_peak_slabs_in_use, name); | ||
if (title_printed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be allways printed, so not sure why we have if here
src/pool/pool_disjoint.c
Outdated
} | ||
|
||
disjoint_pool_t *disjoint_pool = | ||
(disjoint_pool_t *)umf_ba_global_alloc(sizeof(struct disjoint_pool_t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed cast
sizeof(*disjoint_pool)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pool/pool_disjoint.c
Outdated
|
||
umf_result_t disjoint_pool_initialize(umf_memory_provider_handle_t provider, | ||
void *params, void **ppPool) { | ||
if (!provider) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check other arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/pool/pool_disjoint_internal.h
Outdated
// Available list if any one or more of their chunks is free.The entire slab | ||
// is not necessarily free, just some chunks in the slab are free. To | ||
// implement pooling we will allow one slab in the Available list to be | ||
// entirely empty. Normally such a slab would have been freed. But |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to describe what API does, not what it doesn't do, to avoid confusion. Normally(..)
sentence could be dropped. Same below before Instead(...)
.
src/pool/pool_disjoint_internal.h
Outdated
// Protects the bucket and all the corresponding slabs | ||
utils_mutex_t bucket_lock; | ||
|
||
// Reference to the allocator context, used access memory allocation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
used to access ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
umf_result_t | ||
umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams) { | ||
// NOTE: dereferencing hParams when BA is already destroyed leads to crash | ||
if (hParams && !umf_ba_global_is_destroyed()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall there be some warning when base allocator is already destroyed?
disjoint_pool_print_stats(hPool, &title_printed, &high_bucket_size, | ||
&high_peak_slabs_in_use, name); | ||
if (title_printed) { | ||
LOG_DEBUG("current pool size: %zu", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current -> destroyed ?
if (title_printed) { | ||
LOG_DEBUG("current pool size: %zu", | ||
disjoint_pool_get_limits(hPool)->total_size); | ||
LOG_DEBUG("suggested setting=;%c%s:%zu,%zu,64K", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are destroying a pool, what do we need suggested settings for?
umf_result_t ret = | ||
umfMemoryProviderAlloc(pool->provider, size, 0, &ptr); | ||
if (ret != UMF_RESULT_SUCCESS) { | ||
TLS_last_allocation_error = ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log a failure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
int i = 0; | ||
Size1 = ts1; | ||
Size2 = ts2; | ||
for (; Size2 < CutOff; Size1 *= 2, Size2 *= 2, i += 2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last Size1
bucket won't be created in case 1.5 * Size1 < CutOff
even if Size1 < CutOff
. This should be either created or clearly commented somewhere that this is the case.
|
||
void *disjoint_pool_malloc(void *pool, size_t size) { | ||
disjoint_pool_t *hPool = (disjoint_pool_t *)pool; | ||
void *ptr = disjoint_pool_allocate(hPool, size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for pool == NULL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is already done in umfPoolMalloc
// This allocation will be served from a Bucket which size is multiple | ||
// of Alignment and Slab address is aligned to provider_min_page_size | ||
// so the address will be properly aligned. | ||
aligned_size = (size > 1) ? ALIGN_UP(size, alignment) : alignment; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALIGN_UP_SAFE
?
while (chunk != slab->chunks + slab->num_chunks) { | ||
// false means not used | ||
if (*chunk == false) { | ||
size_t idx = (chunk - slab->chunks) / sizeof(bool); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bool *
pointer arithmetic will already provide the index number. Remove the division by sizeof(bool)
.
6f24a0e
to
6237f6c
Compare
6237f6c
to
64fdb4e
Compare
64fdb4e
to
26e4737
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issues resolved
make Disjoint Pool a C structure. With this PR: