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