@@ -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,180 @@ 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 , (void )indexes ;
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_nr , alloc_count )
207+ DEFINE_STATS_HANDLER (alloc_pool_nr , alloc_pool_count )
208+ DEFINE_STATS_HANDLER (free_nr , 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 ),
216+ CTL_LEAF_RO (reserved_memory ),
217+ CTL_LEAF_RO (alloc_nr ),
218+ CTL_LEAF_RO (alloc_pool_nr ),
219+ CTL_LEAF_RO (free_nr ),
220+ CTL_LEAF_RO (curr_slabs_in_use ),
221+ CTL_LEAF_RO (curr_slabs_in_pool ),
222+ CTL_LEAF_RO (max_slabs_in_use ),
223+ CTL_LEAF_RO (max_slabs_in_pool ),
224+ CTL_NODE_END ,
225+ };
226+
227+ #undef DEFINE_STATS_HANDLER
228+
229+ #ifdef UMF_DEVELOPER_MODE
230+ #define VALIDATE_BUCKETS_NAME (indexes ) \
231+ if (strcmp("buckets", indexes->name) != 0) { \
232+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
233+ }
234+ #else
235+ #define VALIDATE_BUCKETS_NAME (indexes ) \
236+ do { \
237+ } while (0);
238+ #endif
239+
240+ #define DEFINE_BUCKET_STATS_HANDLER (NAME , MEMBER ) \
241+ static umf_result_t CTL_READ_HANDLER(NAME, perBucket)( \
242+ void *ctx, umf_ctl_query_source_t source, void *arg, size_t size, \
243+ umf_ctl_index_utlist_t *indexes) { \
244+ (void)source; \
245+ \
246+ disjoint_pool_t *pool = (disjoint_pool_t *)ctx; \
247+ if (arg == NULL || size != sizeof(size_t)) { \
248+ LOG_ERR("arg is NULL or size is not sizeof(size_t)"); \
249+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
250+ } \
251+ \
252+ VALIDATE_BUCKETS_NAME(indexes); \
253+ if (strcmp(#MEMBER, "size") != 0 && !pool->params.pool_trace) { \
254+ LOG_ERR("pool trace is disabled, cannot read " #NAME); \
255+ return UMF_RESULT_ERROR_NOT_SUPPORTED; \
256+ } \
257+ \
258+ size_t idx; \
259+ idx = *(size_t *)indexes->arg; \
260+ \
261+ if (idx >= pool->buckets_num) { \
262+ LOG_ERR("bucket id %zu is out of range [0, %zu)", idx, \
263+ pool->buckets_num); \
264+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
265+ } \
266+ \
267+ bucket_t *bucket = pool->buckets[idx]; \
268+ *(size_t *)arg = bucket->MEMBER; \
269+ \
270+ return UMF_RESULT_SUCCESS; \
271+ }
272+
273+ DEFINE_BUCKET_STATS_HANDLER (alloc_nr , alloc_count )
274+ DEFINE_BUCKET_STATS_HANDLER (alloc_pool_nr , alloc_pool_count )
275+ DEFINE_BUCKET_STATS_HANDLER (free_nr , free_count )
276+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_use , curr_slabs_in_use )
277+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_pool , curr_slabs_in_pool )
278+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_use , max_slabs_in_use )
279+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_pool , max_slabs_in_pool )
280+
281+ static const umf_ctl_node_t CTL_NODE (stats , perBucket )[] = {
282+ CTL_LEAF_RO (alloc_nr , perBucket ),
283+ CTL_LEAF_RO (alloc_pool_nr , perBucket ),
284+ CTL_LEAF_RO (free_nr , perBucket ),
285+ CTL_LEAF_RO (curr_slabs_in_use , perBucket ),
286+ CTL_LEAF_RO (curr_slabs_in_pool , perBucket ),
287+ CTL_LEAF_RO (max_slabs_in_use , perBucket ),
288+ CTL_LEAF_RO (max_slabs_in_pool , perBucket ),
289+ CTL_NODE_END ,
290+ };
291+
292+ // Not a counter; but it is read exactly like other per-bucket stats, so we can use macro.
293+ DEFINE_BUCKET_STATS_HANDLER (size , size )
294+
295+ #undef DEFINE_BUCKET_STATS_HANDLER
296+
297+ static const umf_ctl_node_t CTL_NODE (buckets )[] = {
298+ CTL_LEAF_RO (count ), CTL_LEAF_RO (size , perBucket ),
299+ CTL_CHILD (stats , perBucket ), CTL_NODE_END };
300+
301+ static int bucket_id_parser (const void * arg , void * dest , size_t dest_size ) {
302+ size_t * out = (size_t * )dest ;
303+
304+ if (arg == NULL ) {
305+ * out = SIZE_MAX ;
306+ return 1 ; // node n
307+ }
308+
309+ int ret = ctl_arg_unsigned (arg , dest , dest_size );
310+ if (ret ) {
311+ * out = SIZE_MAX ;
312+ return 1 ;
313+ }
314+
315+ return 0 ;
316+ }
317+
318+ static const struct ctl_argument CTL_ARG (buckets ) = {
319+ sizeof (size_t ),
320+ {{0 , sizeof (size_t ), CTL_ARG_TYPE_UNSIGNED_LONG_LONG , bucket_id_parser },
321+ CTL_ARG_PARSER_END }};
153322
154323static void initialize_disjoint_ctl (void ) {
155324 CTL_REGISTER_MODULE (& disjoint_ctl_root , stats );
156- // CTL_REGISTER_MODULE(&disjoint_ctl_root, name);
325+ CTL_REGISTER_MODULE (& disjoint_ctl_root , buckets );
326+ // TODO: this is hack. Need some way to register module as node with argument
327+ disjoint_ctl_root .root [disjoint_ctl_root .first_free - 1 ].arg =
328+ & CTL_ARG (buckets );
157329}
158330
159331umf_result_t disjoint_pool_ctl (void * hPool ,
0 commit comments