@@ -44,6 +44,7 @@ static umf_result_t CTL_READ_HANDLER(name)(void *ctx,
4444 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
4545
4646 if (arg == NULL ) {
47+ LOG_ERR ("arg is NULL" );
4748 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
4849 }
4950
@@ -64,6 +65,7 @@ static umf_result_t CTL_WRITE_HANDLER(name)(void *ctx,
6465 (void )source , (void )indexes , (void )size ;
6566 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
6667 if (arg == NULL ) {
68+ LOG_ERR ("arg is NULL" );
6769 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
6870 }
6971
@@ -81,6 +83,7 @@ CTL_READ_HANDLER(used_memory)(void *ctx, umf_ctl_query_source_t source,
8183 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
8284
8385 if (arg == NULL || size != sizeof (size_t )) {
86+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
8487 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
8588 }
8689
@@ -119,6 +122,7 @@ CTL_READ_HANDLER(reserved_memory)(void *ctx, umf_ctl_query_source_t source,
119122 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
120123
121124 if (arg == NULL || size != sizeof (size_t )) {
125+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
122126 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
123127 }
124128
@@ -148,12 +152,175 @@ CTL_READ_HANDLER(reserved_memory)(void *ctx, umf_ctl_query_source_t source,
148152 return UMF_RESULT_SUCCESS ;
149153}
150154
151- static const umf_ctl_node_t CTL_NODE (stats )[] = {CTL_LEAF_RO (used_memory ),
152- CTL_LEAF_RO (reserved_memory )};
155+ static umf_result_t CTL_READ_HANDLER (count )(void * ctx ,
156+ umf_ctl_query_source_t source ,
157+ void * arg , size_t size ,
158+ umf_ctl_index_utlist_t * indexes ) {
159+ (void )source ;
160+
161+ disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
162+ if (arg == NULL || size != sizeof (size_t )) {
163+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
164+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
165+ }
166+
167+ if (* (size_t * )indexes -> arg != SIZE_MAX ) {
168+ LOG_ERR ("to read bucket count, you must call it without bucket id" );
169+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
170+ }
171+ * (size_t * )arg = pool -> buckets_num ;
172+
173+ return UMF_RESULT_SUCCESS ;
174+ }
175+
176+ #define DEFINE_STATS_HANDLER (NAME , MEMBER ) \
177+ static umf_result_t CTL_READ_HANDLER(NAME)( \
178+ void *ctx, umf_ctl_query_source_t source, void *arg, size_t size, \
179+ umf_ctl_index_utlist_t *indexes) { \
180+ (void)source; \
181+ (void)indexes; \
182+ disjoint_pool_t *pool = (disjoint_pool_t *)ctx; \
183+ \
184+ if (arg == NULL || size != sizeof(size_t)) { \
185+ LOG_ERR("arg is NULL or size is not sizeof(size_t)"); \
186+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
187+ } \
188+ \
189+ if (!pool->params.pool_trace) { \
190+ LOG_ERR("pool trace is disabled, cannot read " #NAME); \
191+ return UMF_RESULT_ERROR_NOT_SUPPORTED; \
192+ } \
193+ \
194+ size_t total = 0; \
195+ for (size_t i = 0; i < pool->buckets_num; ++i) { \
196+ bucket_t *bucket = pool->buckets[i]; \
197+ utils_mutex_lock(&bucket->bucket_lock); \
198+ total += bucket->MEMBER; \
199+ utils_mutex_unlock(&bucket->bucket_lock); \
200+ } \
201+ \
202+ *(size_t *)arg = total; \
203+ return UMF_RESULT_SUCCESS; \
204+ }
205+
206+ DEFINE_STATS_HANDLER (alloc_num , alloc_count )
207+ DEFINE_STATS_HANDLER (alloc_pool_num , alloc_pool_count )
208+ DEFINE_STATS_HANDLER (free_num , free_count )
209+ DEFINE_STATS_HANDLER (curr_slabs_in_use , curr_slabs_in_use )
210+ DEFINE_STATS_HANDLER (curr_slabs_in_pool , curr_slabs_in_pool )
211+ DEFINE_STATS_HANDLER (max_slabs_in_use , max_slabs_in_use )
212+ DEFINE_STATS_HANDLER (max_slabs_in_pool , max_slabs_in_pool )
213+
214+ static const umf_ctl_node_t CTL_NODE (stats )[] = {
215+ CTL_LEAF_RO (used_memory ), CTL_LEAF_RO (reserved_memory ),
216+ CTL_LEAF_RO (alloc_num ), CTL_LEAF_RO (alloc_pool_num ),
217+ CTL_LEAF_RO (free_num ), CTL_LEAF_RO (curr_slabs_in_use ),
218+ CTL_LEAF_RO (curr_slabs_in_pool ), CTL_LEAF_RO (max_slabs_in_use ),
219+ CTL_LEAF_RO (max_slabs_in_pool ), CTL_NODE_END ,
220+ };
221+
222+ #undef DEFINE_STATS_HANDLER
223+
224+ #ifdef UMF_DEVELOPER_MODE
225+ #define VALIDATE_BUCKETS_NAME (indexes ) \
226+ if (strcmp("buckets", indexes->name) != 0) { \
227+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
228+ }
229+ #else
230+ #define VALIDATE_BUCKETS_NAME (indexes ) \
231+ do { \
232+ } while (0);
233+ #endif
234+
235+ #define DEFINE_BUCKET_STATS_HANDLER (NAME , MEMBER ) \
236+ static umf_result_t CTL_READ_HANDLER(NAME, perBucket)( \
237+ void *ctx, umf_ctl_query_source_t source, void *arg, size_t size, \
238+ umf_ctl_index_utlist_t *indexes) { \
239+ (void)source; \
240+ \
241+ disjoint_pool_t *pool = (disjoint_pool_t *)ctx; \
242+ if (arg == NULL || size != sizeof(size_t)) { \
243+ LOG_ERR("arg is NULL or size is not sizeof(size_t)"); \
244+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
245+ } \
246+ \
247+ VALIDATE_BUCKETS_NAME(indexes); \
248+ if (strcmp(#MEMBER, "size") != 0 && !pool->params.pool_trace) { \
249+ LOG_ERR("pool trace is disabled, cannot read " #NAME); \
250+ return UMF_RESULT_ERROR_NOT_SUPPORTED; \
251+ } \
252+ \
253+ size_t idx; \
254+ idx = *(size_t *)indexes->arg; \
255+ \
256+ if (idx >= pool->buckets_num) { \
257+ LOG_ERR("bucket id %zu is out of range [0, %zu)", idx, \
258+ pool->buckets_num); \
259+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
260+ } \
261+ \
262+ bucket_t *bucket = pool->buckets[idx]; \
263+ *(size_t *)arg = bucket->MEMBER; \
264+ \
265+ return UMF_RESULT_SUCCESS; \
266+ }
267+
268+ DEFINE_BUCKET_STATS_HANDLER (alloc_num , alloc_count )
269+ DEFINE_BUCKET_STATS_HANDLER (alloc_pool_num , alloc_pool_count )
270+ DEFINE_BUCKET_STATS_HANDLER (free_num , free_count )
271+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_use , curr_slabs_in_use )
272+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_pool , curr_slabs_in_pool )
273+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_use , max_slabs_in_use )
274+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_pool , max_slabs_in_pool )
275+
276+ static const umf_ctl_node_t CTL_NODE (stats , perBucket )[] = {
277+ CTL_LEAF_RO (alloc_num , perBucket ),
278+ CTL_LEAF_RO (alloc_pool_num , perBucket ),
279+ CTL_LEAF_RO (free_num , perBucket ),
280+ CTL_LEAF_RO (curr_slabs_in_use , perBucket ),
281+ CTL_LEAF_RO (curr_slabs_in_pool , perBucket ),
282+ CTL_LEAF_RO (max_slabs_in_use , perBucket ),
283+ CTL_LEAF_RO (max_slabs_in_pool , perBucket ),
284+ CTL_NODE_END ,
285+ };
286+
287+ // Not a counter; but it is read exactly like other per-bucket stats, so we can use macro.
288+ DEFINE_BUCKET_STATS_HANDLER (size , size )
289+
290+ #undef DEFINE_BUCKET_STATS_HANDLER
291+
292+ static const umf_ctl_node_t CTL_NODE (buckets )[] = {
293+ CTL_LEAF_RO (count ), CTL_LEAF_RO (size , perBucket ),
294+ CTL_CHILD (stats , perBucket ), CTL_NODE_END };
295+
296+ static int bucket_id_parser (const void * arg , void * dest , size_t dest_size ) {
297+ size_t * out = (size_t * )dest ;
298+
299+ if (arg == NULL ) {
300+ * out = SIZE_MAX ;
301+ return 1 ; // node n
302+ }
303+
304+ int ret = ctl_arg_unsigned (arg , dest , dest_size );
305+ if (ret ) {
306+ * out = SIZE_MAX ;
307+ return 1 ;
308+ }
309+
310+ return 0 ;
311+ }
312+
313+ static const struct ctl_argument CTL_ARG (buckets ) = {
314+ sizeof (size_t ),
315+ {{0 , sizeof (size_t ), CTL_ARG_TYPE_UNSIGNED_LONG_LONG , bucket_id_parser },
316+ CTL_ARG_PARSER_END }};
153317
154318static void initialize_disjoint_ctl (void ) {
155319 CTL_REGISTER_MODULE (& disjoint_ctl_root , stats );
156- // CTL_REGISTER_MODULE(&disjoint_ctl_root, name);
320+ CTL_REGISTER_MODULE (& disjoint_ctl_root , buckets );
321+ // TODO: this is hack. Need some way to register module as node with argument
322+ disjoint_ctl_root .root [disjoint_ctl_root .first_free - 1 ].arg =
323+ & CTL_ARG (buckets );
157324}
158325
159326umf_result_t disjoint_pool_ctl (void * hPool ,
0 commit comments