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