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