svm: improve fifo segment show
[vpp.git] / src / svm / fifo_segment.c
1 /*
2  * Copyright (c) 2016-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <svm/fifo_segment.h>
17
18 /**
19  * Fifo segment free space
20  *
21  * Queries the underlying memory manager, dlmalloc, for free space. Since this
22  * ends up walking the internal data structures, it should not be called
23  * indiscriminately.
24  *
25  * @param fs            fifo segment
26  * @return              number of free bytes
27  */
28 static u32
29 fs_free_space (fifo_segment_t * fs)
30 {
31   struct dlmallinfo dlminfo;
32
33   dlminfo = mspace_mallinfo (fs->ssvm.sh->heap);
34   return dlminfo.fordblks;
35 }
36
37 /**
38  * Initialize fifo segment shared header
39  */
40 int
41 fifo_segment_init (fifo_segment_t * fs)
42 {
43   fifo_segment_header_t *fsh;
44   ssvm_shared_header_t *sh;
45   void *oldheap;
46
47   sh = fs->ssvm.sh;
48   oldheap = ssvm_push_heap (sh);
49
50   fsh = clib_mem_alloc (sizeof (*fsh));
51   clib_memset (fsh, 0, sizeof (*fsh));
52   fs->h = sh->opaque[0] = fsh;
53
54   ssvm_pop_heap (oldheap);
55
56   fsh->n_free_bytes = fs_free_space (fs);
57   sh->ready = 1;
58   return (0);
59 }
60
61 /**
62  * Create a fifo segment and initialize as master
63  */
64 int
65 fifo_segment_create (fifo_segment_main_t * sm, fifo_segment_create_args_t * a)
66 {
67   fifo_segment_t *fs;
68   uword baseva;
69   int rv;
70
71   /* Allocate a fresh segment */
72   pool_get_zero (sm->segments, fs);
73
74   baseva = a->segment_type == SSVM_SEGMENT_PRIVATE ? ~0ULL : sm->next_baseva;
75   fs->ssvm.ssvm_size = a->segment_size;
76   fs->ssvm.i_am_master = 1;
77   fs->ssvm.my_pid = getpid ();
78   fs->ssvm.name = format (0, "%s%c", a->segment_name, 0);
79   fs->ssvm.requested_va = baseva;
80
81   if ((rv = ssvm_master_init (&fs->ssvm, a->segment_type)))
82     {
83       pool_put (sm->segments, fs);
84       return (rv);
85     }
86
87   /* Note: requested_va updated due to seg base addr randomization */
88   sm->next_baseva = fs->ssvm.sh->ssvm_va + fs->ssvm.ssvm_size;
89
90   fifo_segment_init (fs);
91   vec_add1 (a->new_segment_indices, fs - sm->segments);
92   return (0);
93 }
94
95 /**
96  * Attach as slave to a fifo segment
97  */
98 int
99 fifo_segment_attach (fifo_segment_main_t * sm, fifo_segment_create_args_t * a)
100 {
101   fifo_segment_t *s;
102   int rv;
103
104   pool_get_zero (sm->segments, s);
105
106   s->ssvm.ssvm_size = a->segment_size;
107   s->ssvm.my_pid = getpid ();
108   s->ssvm.name = format (0, "%s%c", a->segment_name, 0);
109   s->ssvm.requested_va = sm->next_baseva;
110   if (a->segment_type == SSVM_SEGMENT_MEMFD)
111     s->ssvm.fd = a->memfd_fd;
112   else
113     s->ssvm.attach_timeout = sm->timeout_in_seconds;
114
115   if ((rv = ssvm_slave_init (&s->ssvm, a->segment_type)))
116     {
117       _vec_len (s) = vec_len (s) - 1;
118       return (rv);
119     }
120
121   /* Fish the segment header */
122   s->h = s->ssvm.sh->opaque[0];
123
124   vec_add1 (a->new_segment_indices, s - sm->segments);
125   return (0);
126 }
127
128 void
129 fifo_segment_delete (fifo_segment_main_t * sm, fifo_segment_t * s)
130 {
131   ssvm_delete (&s->ssvm);
132   clib_memset (s, 0xfe, sizeof (*s));
133   pool_put (sm->segments, s);
134 }
135
136 u32
137 fifo_segment_index (fifo_segment_main_t * sm, fifo_segment_t * s)
138 {
139   return s - sm->segments;
140 }
141
142 void *
143 svm_fifo_segment_heap (fifo_segment_t * seg)
144 {
145   return seg->ssvm.sh->heap;
146 }
147
148 fifo_segment_t *
149 fifo_segment_get_segment (fifo_segment_main_t * sm, u32 segment_index)
150 {
151   return pool_elt_at_index (sm->segments, segment_index);
152 }
153
154 void
155 fifo_segment_info (fifo_segment_t * seg, char **address, size_t * size)
156 {
157   *address = (char *) seg->ssvm.sh->ssvm_va;
158   *size = seg->ssvm.ssvm_size;
159 }
160
161 void
162 fifo_segment_main_init (fifo_segment_main_t * sm, u64 baseva,
163                         u32 timeout_in_seconds)
164 {
165   sm->next_baseva = baseva;
166   sm->timeout_in_seconds = timeout_in_seconds;
167 }
168
169 static inline u32
170 fs_freelist_for_size (u32 size)
171 {
172   return max_log2 (size) - max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE);
173 }
174
175 static inline u32
176 fs_freelist_index_to_size (u32 fl_index)
177 {
178   return 1 << (fl_index + max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE));
179 }
180
181 static inline int
182 fs_chunk_size_is_valid (u32 size)
183 {
184   /*
185    * 4K minimum. It's not likely that anything good will happen
186    * with a smaller FIFO.
187    */
188   return size >= FIFO_SEGMENT_MIN_FIFO_SIZE
189     && size <= FIFO_SEGMENT_MAX_FIFO_SIZE;
190 }
191
192 static svm_fifo_t *
193 fs_try_alloc_fifo_freelist (fifo_segment_t * fs, u32 fl_index, u32 data_bytes)
194 {
195   fifo_segment_header_t *fsh = fs->h;
196   svm_fifo_chunk_t *c;
197   svm_fifo_t *f;
198
199   f = fsh->free_fifos;
200   c = fsh->free_chunks[fl_index];
201
202   if (!f || !c)
203     return 0;
204
205   fsh->free_fifos = f->next;
206   fsh->free_chunks[fl_index] = c->next;
207   c->next = c;
208   c->start_byte = 0;
209   c->length = data_bytes;
210   memset (f, 0, sizeof (*f));
211   f->start_chunk = c;
212   f->end_chunk = c;
213
214   fsh->n_fl_chunk_bytes -= fs_freelist_index_to_size (fl_index);
215   return f;
216 }
217
218 static svm_fifo_t *
219 fs_try_alloc_fifo_freelist_multi_chunk (fifo_segment_t * fs, u32 data_bytes)
220 {
221   svm_fifo_chunk_t *c, *first = 0, *last = 0;
222   fifo_segment_header_t *fsh = fs->h;
223   u32 fl_index, fl_size, n_alloc = 0;
224   svm_fifo_t *f;
225
226   f = fsh->free_fifos;
227   if (!f)
228     {
229       void *oldheap = ssvm_push_heap (fs->ssvm.sh);
230       f = clib_mem_alloc_aligned (sizeof (*f), CLIB_CACHE_LINE_BYTES);
231       ssvm_pop_heap (oldheap);
232       if (!f)
233         return 0;
234       memset (f, 0, sizeof (*f));
235     }
236
237   fl_index = fs_freelist_for_size (data_bytes) - 1;
238   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
239   fl_size = fs_freelist_index_to_size (fl_index);
240
241   while (data_bytes)
242     {
243       c = fsh->free_chunks[fl_index];
244       if (c)
245         {
246           fsh->free_chunks[fl_index] = c->next;
247           if (!last)
248             last = c;
249           c->next = first;
250           first = c;
251           n_alloc += c->length;
252           c->length = clib_min (fl_size, data_bytes);
253           data_bytes -= c->length;
254         }
255       else
256         {
257           ASSERT (fl_index > 0);
258           fl_index -= 1;
259           fl_size = fl_size >> 1;
260         }
261     }
262   f->start_chunk = first;
263   f->end_chunk = last;
264   last->next = first;
265   fsh->n_fl_chunk_bytes -= n_alloc;
266   return f;
267 }
268
269 static int
270 fs_try_alloc_fifo_batch (fifo_segment_t * fs, u32 fl_index, u32 batch_size)
271 {
272   fifo_segment_header_t *fsh = fs->h;
273   u32 size, hdrs, rounded_data_size;
274   svm_fifo_chunk_t *c;
275   svm_fifo_t *f;
276   void *oldheap;
277   u8 *fmem;
278   int i;
279
280   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
281   rounded_data_size = fs_freelist_index_to_size (fl_index);
282   hdrs = sizeof (*f) + sizeof (*c);
283   size = (hdrs + rounded_data_size) * batch_size;
284
285   oldheap = ssvm_push_heap (fs->ssvm.sh);
286   fmem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES,
287                                            0 /* align_offset */ ,
288                                            0 /* os_out_of_memory */ );
289   ssvm_pop_heap (oldheap);
290
291   /* Out of space.. */
292   if (fmem == 0)
293     return -1;
294
295   /* Carve fifo + chunk space */
296   for (i = 0; i < batch_size; i++)
297     {
298       f = (svm_fifo_t *) fmem;
299       memset (f, 0, sizeof (*f));
300       f->next = fsh->free_fifos;
301       fsh->free_fifos = f;
302       c = (svm_fifo_chunk_t *) (fmem + sizeof (*f));
303       c->start_byte = 0;
304       c->length = rounded_data_size;
305       c->next = fsh->free_chunks[fl_index];
306       fsh->free_chunks[fl_index] = c;
307       fmem += hdrs + rounded_data_size;
308     }
309
310   fsh->n_fl_chunk_bytes += batch_size * rounded_data_size;
311   fsh->n_free_bytes -= size;
312
313   return 0;
314 }
315
316 /**
317  * Try to allocate new fifo
318  *
319  * Tries the following steps in order:
320  * - grab fifo and chunk from freelists
321  * - batch fifo and chunk allocation
322  * - single fifo allocation
323  * - grab multiple fifo chunks from freelists
324  */
325 static svm_fifo_t *
326 fs_try_alloc_fifo (fifo_segment_t * fs, u32 data_bytes)
327 {
328   fifo_segment_header_t *fsh = fs->h;
329   u32 fifo_sz, fl_index;
330   svm_fifo_t *f = 0;
331
332   fl_index = fs_freelist_for_size (data_bytes);
333   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
334   fifo_sz = sizeof (svm_fifo_t) + sizeof (svm_fifo_chunk_t);
335   fifo_sz += 1 << max_log2 (data_bytes);
336
337   if (fsh->free_fifos && fsh->free_chunks[fl_index])
338     {
339       f = fs_try_alloc_fifo_freelist (fs, fl_index, data_bytes);
340       if (f)
341         goto done;
342     }
343   if (fifo_sz * FIFO_SEGMENT_ALLOC_BATCH_SIZE < fsh->n_free_bytes)
344     {
345       if (fs_try_alloc_fifo_batch (fs, fl_index,
346                                    FIFO_SEGMENT_ALLOC_BATCH_SIZE))
347         goto done;
348
349       f = fs_try_alloc_fifo_freelist (fs, fl_index, data_bytes);
350       goto done;
351     }
352   if (fifo_sz <= fsh->n_free_bytes)
353     {
354       void *oldheap = ssvm_push_heap (fs->ssvm.sh);
355       f = svm_fifo_create (data_bytes);
356       ssvm_pop_heap (oldheap);
357       if (f)
358         {
359           fsh->n_free_bytes -= fifo_sz;
360           goto done;
361         }
362     }
363   if (data_bytes <= fsh->n_fl_chunk_bytes)
364     f = fs_try_alloc_fifo_freelist_multi_chunk (fs, data_bytes);
365
366 done:
367
368   return f;
369 }
370
371 /**
372  * Allocate fifo in fifo segment
373  */
374 svm_fifo_t *
375 fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
376                          fifo_segment_ftype_t ftype)
377 {
378   fifo_segment_header_t *fsh;
379   svm_fifo_t *f = 0;
380
381   if (!fs_chunk_size_is_valid (data_bytes))
382     {
383       clib_warning ("fifo size out of range %d", data_bytes);
384       return 0;
385     }
386
387   fsh = fs->h;
388   ssvm_lock_non_recursive (fs->ssvm.sh, 1);
389
390   f = fs_try_alloc_fifo (fs, data_bytes);
391   if (!f)
392     goto done;
393
394   /* (re)initialize the fifo, as in svm_fifo_create */
395   svm_fifo_init (f, data_bytes);
396
397   /* If rx fifo type add to active fifos list. When cleaning up segment,
398    * we need a list of active sessions that should be disconnected. Since
399    * both rx and tx fifos keep pointers to the session, it's enough to track
400    * only one. */
401   if (ftype == FIFO_SEGMENT_RX_FIFO)
402     {
403       if (fsh->fifos)
404         {
405           fsh->fifos->prev = f;
406           f->next = fsh->fifos;
407         }
408       fsh->fifos = f;
409       f->flags |= SVM_FIFO_F_LL_TRACKED;
410     }
411   fsh->n_active_fifos++;
412
413 done:
414   ssvm_unlock_non_recursive (fs->ssvm.sh);
415   return (f);
416 }
417
418 /**
419  * Free fifo allocated in fifo segment
420  */
421 void
422 fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
423 {
424   svm_fifo_chunk_t *cur, *next;
425   fifo_segment_header_t *fsh;
426   ssvm_shared_header_t *sh;
427   void *oldheap;
428   int fl_index;
429
430   ASSERT (f->refcnt > 0);
431
432   if (--f->refcnt > 0)
433     return;
434
435   sh = fs->ssvm.sh;
436   fsh = fs->h;
437
438   ssvm_lock_non_recursive (sh, 2);
439
440   /* Remove from active list. Only rx fifos are tracked */
441   if (f->flags & SVM_FIFO_F_LL_TRACKED)
442     {
443       if (f->prev)
444         f->prev->next = f->next;
445       else
446         fsh->fifos = f->next;
447       if (f->next)
448         f->next->prev = f->prev;
449       f->flags &= ~SVM_FIFO_F_LL_TRACKED;
450     }
451
452   /* Add to free list */
453   f->next = fsh->free_fifos;
454   f->prev = 0;
455   fsh->free_fifos = f;
456
457   /* Free fifo chunks */
458   cur = f->start_chunk;
459   do
460     {
461       next = cur->next;
462       fl_index = fs_freelist_for_size (cur->length);
463       ASSERT (fl_index < vec_len (fsh->free_chunks));
464       cur->next = fsh->free_chunks[fl_index];
465       fsh->free_chunks[fl_index] = cur;
466       fsh->n_fl_chunk_bytes += fs_freelist_index_to_size (fl_index);
467       cur = next;
468     }
469   while (cur != f->start_chunk);
470
471   oldheap = ssvm_push_heap (sh);
472   svm_fifo_free_chunk_lookup (f);
473   ssvm_pop_heap (oldheap);
474
475   /* not allocated on segment heap */
476   svm_fifo_free_ooo_data (f);
477
478   if (CLIB_DEBUG)
479     {
480       f->master_session_index = ~0;
481       f->master_thread_index = ~0;
482     }
483
484   fsh->n_active_fifos--;
485   ssvm_unlock_non_recursive (sh);
486 }
487
488 int
489 fifo_segment_prealloc_fifo_hdrs (fifo_segment_t * fs, u32 batch_size)
490 {
491   fifo_segment_header_t *fsh = fs->h;
492   svm_fifo_t *f;
493   void *oldheap;
494   u32 size;
495   u8 *fmem;
496   int i;
497
498   size = (sizeof (*f)) * batch_size;
499
500   oldheap = ssvm_push_heap (fs->ssvm.sh);
501   fmem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES,
502                                            0 /* align_offset */ ,
503                                            0 /* os_out_of_memory */ );
504   ssvm_pop_heap (oldheap);
505
506   /* Out of space.. */
507   if (fmem == 0)
508     return -1;
509
510   /* Carve fifo + chunk space */
511   for (i = 0; i < batch_size; i++)
512     {
513       f = (svm_fifo_t *) fmem;
514       memset (f, 0, sizeof (*f));
515       f->next = fsh->free_fifos;
516       fsh->free_fifos = f;
517       fmem += sizeof (*f);
518     }
519
520   fsh->n_free_bytes -= size;
521
522   return 0;
523 }
524
525 int
526 fifo_segment_prealloc_fifo_chunks (fifo_segment_t * fs, u32 chunk_size,
527                                    u32 batch_size)
528 {
529   fifo_segment_header_t *fsh = fs->h;
530   u32 size, rounded_data_size, fl_index;
531   svm_fifo_chunk_t *c;
532   void *oldheap;
533   u8 *cmem;
534   int i;
535
536   if (!fs_chunk_size_is_valid (chunk_size))
537     {
538       clib_warning ("chunk size out of range %d", chunk_size);
539       return -1;
540     }
541
542   fl_index = fs_freelist_for_size (chunk_size);
543   vec_validate_init_empty (fsh->free_chunks, fl_index, 0);
544   rounded_data_size = fs_freelist_index_to_size (fl_index);
545   size = (sizeof (*c) + rounded_data_size) * batch_size;
546
547   oldheap = ssvm_push_heap (fs->ssvm.sh);
548   cmem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES,
549                                            0 /* align_offset */ ,
550                                            0 /* os_out_of_memory */ );
551   ssvm_pop_heap (oldheap);
552
553   /* Out of space.. */
554   if (cmem == 0)
555     return -1;
556
557   /* Carve fifo + chunk space */
558   for (i = 0; i < batch_size; i++)
559     {
560       c = (svm_fifo_chunk_t *) cmem;
561       c->start_byte = 0;
562       c->length = rounded_data_size;
563       c->next = fsh->free_chunks[fl_index];
564       fsh->free_chunks[fl_index] = c;
565       cmem += sizeof (*c) + rounded_data_size;
566     }
567
568   fsh->n_fl_chunk_bytes += batch_size * rounded_data_size;
569   fsh->n_free_bytes -= size;
570
571   return 0;
572 }
573
574 /**
575  * Pre-allocates fifo pairs in fifo segment
576  */
577 void
578 fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs,
579                                      u32 rx_fifo_size, u32 tx_fifo_size,
580                                      u32 * n_fifo_pairs)
581 {
582   u32 rx_rounded_data_size, tx_rounded_data_size, pair_size, pairs_to_alloc;
583   int rx_fl_index, tx_fl_index;
584   uword space_available;
585   u32 hdrs;
586
587   /* Parameter check */
588   if (rx_fifo_size == 0 || tx_fifo_size == 0 || *n_fifo_pairs == 0)
589     return;
590
591   if (!fs_chunk_size_is_valid (rx_fifo_size))
592     {
593       clib_warning ("rx fifo_size out of range %d", rx_fifo_size);
594       return;
595     }
596
597   if (!fs_chunk_size_is_valid (tx_fifo_size))
598     {
599       clib_warning ("tx fifo_size out of range %d", tx_fifo_size);
600       return;
601     }
602
603   rx_rounded_data_size = (1 << (max_log2 (rx_fifo_size)));
604   rx_fl_index = fs_freelist_for_size (rx_fifo_size);
605   tx_rounded_data_size = (1 << (max_log2 (tx_fifo_size)));
606   tx_fl_index = fs_freelist_for_size (tx_fifo_size);
607
608   hdrs = sizeof (svm_fifo_t) + sizeof (svm_fifo_chunk_t);
609
610   /* Calculate space requirements */
611   pair_size = 2 * hdrs + rx_rounded_data_size + tx_rounded_data_size;
612   space_available = fs_free_space (fs);
613   pairs_to_alloc = clib_min (space_available / pair_size, *n_fifo_pairs);
614
615   if (fs_try_alloc_fifo_batch (fs, rx_fl_index, pairs_to_alloc))
616     clib_warning ("rx prealloc failed");
617   if (fs_try_alloc_fifo_batch (fs, tx_fl_index, pairs_to_alloc))
618     clib_warning ("tx prealloc failed");
619
620   /* Account for the pairs allocated */
621   *n_fifo_pairs -= pairs_to_alloc;
622 }
623
624 int
625 fifo_segment_grow_fifo (fifo_segment_t * fs, svm_fifo_t * f, u32 chunk_size)
626 {
627   ssvm_shared_header_t *sh;
628   svm_fifo_chunk_t *c;
629   void *oldheap;
630   int fl_index;
631
632   if (!fs_chunk_size_is_valid (chunk_size))
633     {
634       clib_warning ("chunk size out of range %d", chunk_size);
635       return 0;
636     }
637
638   fl_index = fs_freelist_for_size (chunk_size);
639
640   sh = fs->ssvm.sh;
641   ssvm_lock_non_recursive (sh, 1);
642
643   vec_validate_init_empty (fs->h->free_chunks, fl_index, 0);
644   c = fs->h->free_chunks[fl_index];
645
646   oldheap = ssvm_push_heap (sh);
647
648   if (!c)
649     {
650       c = svm_fifo_chunk_alloc (chunk_size);
651       if (!c)
652         {
653           ssvm_pop_heap (oldheap);
654           return -1;
655         }
656     }
657   else
658     {
659       fs->h->free_chunks[fl_index] = c->next;
660       c->next = 0;
661     }
662
663   svm_fifo_add_chunk (f, c);
664
665   ssvm_pop_heap (oldheap);
666   ssvm_unlock_non_recursive (sh);
667   return 0;
668 }
669
670 int
671 fifo_segment_collect_fifo_chunks (fifo_segment_t * fs, svm_fifo_t * f)
672 {
673   svm_fifo_chunk_t *cur, *next;
674   ssvm_shared_header_t *sh;
675   void *oldheap;
676   int fl_index;
677
678   sh = fs->ssvm.sh;
679   ssvm_lock_non_recursive (sh, 1);
680
681   oldheap = ssvm_push_heap (sh);
682   cur = svm_fifo_collect_chunks (f);
683
684   while (cur)
685     {
686       next = cur->next;
687       fl_index = fs_freelist_for_size (cur->length);
688       cur->next = fs->h->free_chunks[fl_index];
689       fs->h->free_chunks[fl_index] = cur;
690       cur = next;
691     }
692
693   ssvm_pop_heap (oldheap);
694   ssvm_unlock_non_recursive (sh);
695
696   return 0;
697 }
698
699 /**
700  * Get number of active fifos
701  */
702 u32
703 fifo_segment_num_fifos (fifo_segment_t * fs)
704 {
705   return fs->h->n_active_fifos;
706 }
707
708 u32
709 fifo_segment_num_free_fifos (fifo_segment_t * fs)
710 {
711   fifo_segment_header_t *fsh = fs->h;
712   svm_fifo_t *f;
713   u32 count = 0;
714
715   f = fsh->free_fifos;
716   if (f == 0)
717     return 0;
718
719   while (f)
720     {
721       f = f->next;
722       count++;
723     }
724   return count;
725 }
726
727 u32
728 fifo_segment_num_free_chunks (fifo_segment_t * fs, u32 size)
729 {
730   u32 count = 0, rounded_size, fl_index;
731   fifo_segment_header_t *fsh;
732   svm_fifo_chunk_t *c;
733   int i;
734
735   fsh = fs->h;
736
737   /* Count all free chunks? */
738   if (size == ~0)
739     {
740       for (i = 0; i < vec_len (fsh->free_chunks); i++)
741         {
742           c = fsh->free_chunks[i];
743           if (c == 0)
744             continue;
745
746           while (c)
747             {
748               c = c->next;
749               count++;
750             }
751         }
752       return count;
753     }
754
755   rounded_size = (1 << (max_log2 (size)));
756   fl_index = fs_freelist_for_size (rounded_size);
757
758   if (fl_index >= vec_len (fsh->free_chunks))
759     return 0;
760
761   c = fsh->free_chunks[fl_index];
762   if (c == 0)
763     return 0;
764
765   while (c)
766     {
767       c = c->next;
768       count++;
769     }
770   return count;
771 }
772
773 void
774 fifo_segment_update_free_bytes (fifo_segment_t * fs)
775 {
776   fs->h->n_free_bytes = fs_free_space (fs);
777 }
778
779 u32
780 fifo_segment_free_bytes (fifo_segment_t * fs)
781 {
782   return fs->h->n_free_bytes;
783 }
784
785 u32
786 fifo_segment_chunk_prealloc_bytes (fifo_segment_t * fs)
787 {
788   return fs->h->n_fl_chunk_bytes;
789 }
790
791 u8
792 fifo_segment_has_fifos (fifo_segment_t * fs)
793 {
794   return fs->h->fifos != 0;
795 }
796
797 svm_fifo_t *
798 fifo_segment_get_fifo_list (fifo_segment_t * fs)
799 {
800   return fs->h->fifos;
801 }
802
803 u8 *
804 format_fifo_segment_type (u8 * s, va_list * args)
805 {
806   fifo_segment_t *sp;
807   sp = va_arg (*args, fifo_segment_t *);
808   ssvm_segment_type_t st = ssvm_type (&sp->ssvm);
809
810   if (st == SSVM_SEGMENT_PRIVATE)
811     s = format (s, "%s", "private-heap");
812   else if (st == SSVM_SEGMENT_MEMFD)
813     s = format (s, "%s", "memfd");
814   else if (st == SSVM_SEGMENT_SHM)
815     s = format (s, "%s", "shm");
816   else
817     s = format (s, "%s", "unknown");
818   return s;
819 }
820
821 /**
822  * Segment format function
823  */
824 u8 *
825 format_fifo_segment (u8 * s, va_list * args)
826 {
827   fifo_segment_t *fs = va_arg (*args, fifo_segment_t *);
828   int verbose __attribute__ ((unused)) = va_arg (*args, int);
829   fifo_segment_header_t *fsh;
830   svm_fifo_chunk_t *c;
831   u32 count, indent;
832   u32 active_fifos;
833   u32 free_fifos;
834   char *address;
835   size_t size;
836   int i;
837
838   indent = format_get_indent (s) + 2;
839 #if USE_DLMALLOC == 0
840   s = format (s, "%U segment heap: %U\n", format_white_space, indent,
841               format_mheap, svm_fifo_segment_heap (fs), verbose);
842   s = format (s, "%U segment has %u active fifos\n",
843               format_white_space, indent, fifo_segment_num_fifos (fs));
844 #endif
845
846   if (fs == 0)
847     {
848       s = format (s, "%-15s%15s%15s%15s%15s%15s", "Name", "Type",
849                   "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
850       return s;
851     }
852
853   fsh = fs->h;
854   fifo_segment_info (fs, &address, &size);
855   active_fifos = fifo_segment_num_fifos (fs);
856   free_fifos = fifo_segment_num_free_fifos (fs);
857
858   s = format (s, "%-15v%15U%15llu%15u%15u%15llx", ssvm_name (&fs->ssvm),
859               format_fifo_segment_type, fs, size >> 20ULL, active_fifos,
860               free_fifos, address);
861
862   if (!verbose)
863     return s;
864
865   s = format (s, "\n");
866   for (i = 0; i < vec_len (fsh->free_chunks); i++)
867     {
868       c = fsh->free_chunks[i];
869       if (c == 0)
870         continue;
871       count = 0;
872       while (c)
873         {
874           c = c->next;
875           count++;
876         }
877
878       s = format (s, "%U%-5u Kb: %u free", format_white_space, indent + 2,
879                   1 << (i + max_log2 (FIFO_SEGMENT_MIN_FIFO_SIZE) - 10),
880                   count);
881     }
882   s = format (s, "%Ufree bytes %U", format_white_space, indent + 2,
883               format_memory_size, fsh->n_free_bytes);
884
885   return s;
886 }
887
888 /*
889  * fd.io coding-style-patch-verification: ON
890  *
891  * Local Variables:
892  * eval: (c-set-style "gnu")
893  * End:
894  */