runtime/kp_tab.c - ktap

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. * kp_tab.c - Table handling.
  3. *
  4. * This file is part of ktap by Jovi Zhangwei.
  5. *
  6. * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
  7. *
  8. * Adapted from luajit and lua interpreter.
  9. * Copyright (C) 2005-2014 Mike Pall.
  10. * Copyright (C) 1994-2008 Lua.org, PUC-Rio.
  11. *
  12. * ktap is free software; you can redistribute it and/or modify it
  13. * under the terms and conditions of the GNU General Public License,
  14. * version 2, as published by the Free Software Foundation.
  15. *
  16. * ktap is distributed in the hope it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  19. * more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along with
  22. * this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  24. */

  25. #include <linux/spinlock.h>
  26. #include <linux/module.h>
  27. #include <linux/kallsyms.h>
  28. #include <linux/slab.h>
  29. #include <linux/sort.h>
  30. #include "../include/ktap_types.h"
  31. #include "ktap.h"
  32. #include "kp_vm.h"
  33. #include "kp_obj.h"
  34. #include "kp_str.h"
  35. #include "kp_events.h"
  36. #include "kp_tab.h"

  37. #define tab_lock_init(t)                        \
  38.     do {                                \
  39.         (t)->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;    \
  40.     } while (0)
  41. #define tab_lock(t)                        \
  42.     do {                                \
  43.         local_irq_save(flags);                    \
  44.         arch_spin_lock(&(t)->lock);                \
  45.     } while (0)
  46. #define tab_unlock(t)                        \
  47.     do {                                \
  48.         arch_spin_unlock(&(t)->lock);                \
  49.         local_irq_restore(flags);                \
  50.     } while (0)


  51. const ktap_val_t kp_niltv = { {NULL}, {KTAP_TNIL} } ;
  52. #define niltv  (&kp_niltv)

  53. /* -- Object hashing ------------------------------------------------------ */

  54. /* Hash values are masked with the table hash mask and used as an index. */
  55. static __always_inline
  56. ktap_node_t *hashmask(const ktap_tab_t *t, uint32_t hash)
  57. {
  58.     ktap_node_t *n = t->node;
  59.     return &n[hash & t->hmask];
  60. }

  61. /* String hashes are precomputed when they are interned. */
  62. #define hashstr(t, s)        hashmask(t, (s)->hash)

  63. #define hashlohi(t, lo, hi)    hashmask((t), hashrot((lo), (hi)))
  64. #define hashnum(t, o)        hashlohi((t), (o)->val.n & 0xffffffff, 0)
  65. #define hashgcref(t, o)        hashlohi((t),    \
  66.                 ((unsigned long)(o)->val.gc & 0xffffffff), \
  67.                 ((unsigned long)(o)->val.gc & 0xffffffff) + HASH_BIAS)


  68. /* Hash an arbitrary key and return its anchor position in the hash table. */
  69. static ktap_node_t *hashkey(const ktap_tab_t *t, const ktap_val_t *key)
  70. {
  71.     kp_assert(!tvisint(key));
  72.     if (is_string(key))
  73.         return hashstr(t, rawtsvalue(key));
  74.     else if (is_number(key))
  75.         return hashnum(t, key);
  76.     else if (is_bool(key))
  77.         return hashmask(t, boolvalue(key));
  78.     else
  79.         return hashgcref(t, key);
  80. }

  81. /* -- Table creation and destruction -------------------------------------- */

  82. /* Create new hash part for table. */
  83. static __always_inline
  84. int newhpart(ktap_state_t *ks, ktap_tab_t *t, uint32_t hbits)
  85. {
  86.     uint32_t hsize;
  87.     ktap_node_t *node;
  88.     kp_assert(hbits != 0);

  89.     if (hbits > KP_MAX_HBITS) {
  90.         //kp_error(ks, LJ_ERR_TABOV);
  91.         kp_error(ks, "table overflow\n");
  92.         return -1;
  93.     }
  94.     hsize = 1u << hbits;
  95.     node = vmalloc(hsize * sizeof(ktap_node_t));
  96.     if (!node)
  97.         return -ENOMEM;
  98.     t->freetop = &node[hsize];
  99.     t->node = node;
  100.     t->hmask = hsize-1;

  101.     return 0;
  102. }

  103. /*
  104. * Q: Why all of these copies of t->hmask, t->node etc. to local variables?
  105. * A: Because alias analysis for C is _really_ tough.
  106. *    Even state-of-the-art C compilers won't produce good code without this.
  107. */

  108. /* Clear hash part of table. */
  109. static __always_inline void clearhpart(ktap_tab_t *t)
  110. {
  111.     uint32_t i, hmask = t->hmask;
  112.     ktap_node_t *node = t->node;
  113.     kp_assert(t->hmask != 0);

  114.     for (i = 0; i <= hmask; i++) {
  115.         ktap_node_t *n = &node[i];
  116.         n->next = NULL;
  117.         set_nil(&n->key);
  118.         set_nil(&n->val);
  119.     }

  120.     t->hnum = 0;
  121. }

  122. /* Clear array part of table. */
  123. static __always_inline void clearapart(ktap_tab_t *t)
  124. {
  125.     uint32_t i, asize = t->asize;
  126.     ktap_val_t *array = t->array;
  127.     for (i = 0; i < asize; i++)
  128.         set_nil(&array[i]);
  129. }

  130. /* Create a new table. Note: the slots are not initialized (yet). */
  131. static ktap_tab_t *newtab(ktap_state_t *ks, uint32_t asize, uint32_t hbits)
  132. {
  133.     ktap_tab_t *t;

  134.     t = (ktap_tab_t *)kp_obj_new(ks, sizeof(ktap_tab_t));
  135.     t->gct = ~KTAP_TTAB;
  136.     t->array = NULL;
  137.     t->asize = 0/* In case the array allocation fails. */
  138.     t->hmask = 0;

  139.     tab_lock_init(t);

  140.     if (asize > 0) {
  141.         if (asize > KP_MAX_ASIZE) {
  142.             kp_error(ks, "table overflow\n");
  143.             return NULL;
  144.         }

  145.         t->array = vmalloc(asize * sizeof(ktap_val_t));
  146.         if (!t->array)
  147.             return NULL;
  148.         t->asize = asize;
  149.     }
  150.     if (hbits)
  151.         if (newhpart(ks, t, hbits)) {
  152.             vfree(t->array);
  153.             return NULL;
  154.         }
  155.     return t;
  156. }

  157. /* Create a new table.
  158. *
  159. * The array size is non-inclusive. E.g. asize=128 creates array slots
  160. * for 0..127, but not for 128. If you need slots 1..128, pass asize=129
  161. * (slot 0 is wasted in this case).
  162. *
  163. * The hash size is given in hash bits. hbits=0 means no hash part.
  164. * hbits=1 creates 2 hash slots, hbits=2 creates 4 hash slots and so on.
  165. */
  166. ktap_tab_t *kp_tab_new(ktap_state_t *ks, uint32_t asize, uint32_t hbits)
  167. {
  168.     ktap_tab_t *t = newtab(ks, asize, hbits);
  169.     if (!t)
  170.         return NULL;

  171.     clearapart(t);
  172.     if (t->hmask > 0)
  173.         clearhpart(t);
  174.     return t;
  175. }

  176. #define TABLE_NARR_ENTRIES    255 /* PAGE_SIZE / sizeof(ktap_value) - 1 */
  177. #define TABLE_NREC_ENTRIES    2048 /* (PAGE_SIZE * 20) / sizeof(ktap_tnode)*/

  178. ktap_tab_t *kp_tab_new_ah(ktap_state_t *ks, int32_t a, int32_t h)
  179. {
  180.     if (a == 0 && h == 0) {
  181.         a = TABLE_NARR_ENTRIES;
  182.         h = TABLE_NREC_ENTRIES;
  183.     }

  184.     return kp_tab_new(ks, (uint32_t)(a > 0 ? a+1 : 0), hsize2hbits(h));
  185. }

  186. /* Duplicate a table. */
  187. ktap_tab_t *kp_tab_dup(ktap_state_t *ks, const ktap_tab_t *kt)
  188. {
  189.     ktap_tab_t *t;
  190.     uint32_t asize, hmask;
  191.     int i;

  192.     /* allocate default table size */
  193.     t = kp_tab_new_ah(ks, 0, 0);
  194.     if (!t)
  195.         return NULL;

  196.     asize = kt->asize;
  197.     if (asize > 0) {
  198.         ktap_val_t *array = t->array;
  199.         ktap_val_t *karray = kt->array;
  200.         if (asize < 64) {
  201.             /* An inlined loop beats memcpy for < 512 bytes. */
  202.             uint32_t i;
  203.             for (i = 0; i < asize; i++)
  204.                 set_obj(&array[i], &karray[i]);
  205.         } else {
  206.             memcpy(array, karray, asize*sizeof(ktap_val_t));
  207.         }
  208.     }

  209.     hmask = kt->hmask;
  210.     for (i = 0; i <= hmask; i++) {
  211.         ktap_node_t *knode = &kt->node[i];
  212.         if (is_nil(&knode->key))
  213.             continue;
  214.         kp_tab_set(ks, t, &knode->key, &knode->val);
  215.     }
  216.     return t;
  217. }

  218. /* Clear a table. */
  219. void kp_tab_clear(ktap_tab_t *t)
  220. {
  221.     clearapart(t);
  222.     if (t->hmask > 0) {
  223.         ktap_node_t *node = t->node;
  224.         t->freetop = &node[t->hmask+1];
  225.         clearhpart(t);
  226.     }
  227. }

  228. /* Free a table. */
  229. void kp_tab_free(ktap_state_t *ks, ktap_tab_t *t)
  230. {
  231.     if (t->hmask > 0)
  232.         vfree(t->node);
  233.     if (t->asize > 0)
  234.         vfree(t->array);
  235.     kp_free(ks, t);
  236. }

  237. /* -- Table getters ------------------------------------------------------- */

  238. static const ktap_val_t *tab_getinth(ktap_tab_t *t, uint32_t key)
  239. {
  240.     ktap_val_t k;
  241.     ktap_node_t *n;

  242.     set_number(&k, (ktap_number)key);
  243.     n = hashnum(t, &k);
  244.     do {
  245.         if (is_number(&n->key) && nvalue(&n->key) == key) {
  246.             return &n->val;
  247.         }
  248.     } while ((n = n->next));
  249.     return niltv;
  250. }

  251. static __always_inline
  252. const ktap_val_t *tab_getint(ktap_tab_t *t, uint32_t key)
  253. {
  254.     return ((key < t->asize) ? arrayslot(t, key) :
  255.                    tab_getinth(t, key));
  256. }

  257. void kp_tab_getint(ktap_tab_t *t, uint32_t key, ktap_val_t *val)
  258. {
  259.     unsigned long flags;

  260.     tab_lock(t);
  261.     set_obj(val, tab_getint(t, key));
  262.     tab_unlock(t);
  263. }

  264. static const ktap_val_t *tab_getstr(ktap_tab_t *t, ktap_str_t *key)
  265. {
  266.     ktap_node_t *n = hashstr(t, key);
  267.     do {
  268.         if (is_string(&n->key) && rawtsvalue(&n->key) == key)
  269.             return &n->val;
  270.     } while ((n = n->next));
  271.     return niltv;
  272. }

  273. void kp_tab_getstr(ktap_tab_t *t, ktap_str_t *key, ktap_val_t *val)
  274. {
  275.     unsigned long flags;

  276.     tab_lock(t);
  277.     set_obj(val,  tab_getstr(t, key));
  278.     tab_unlock(t);
  279. }

  280. static const ktap_val_t *tab_get(ktap_state_t *ks, ktap_tab_t *t,
  281.                  const ktap_val_t *key)
  282. {
  283.     if (is_string(key)) {
  284.         return tab_getstr(t, rawtsvalue(key));
  285.     } else if (is_number(key)) {
  286.         ktap_number nk = nvalue(key);
  287.         uint32_t k = (uint32_t)nk;
  288.         if (nk == (ktap_number)k) {
  289.             return tab_getint(t, k);
  290.         } else {
  291.             goto genlookup;    /* Else use the generic lookup. */
  292.         }
  293.     } else if (is_eventstr(key)) {
  294.         const ktap_str_t *ts;

  295.         if (!ks->current_event) {
  296.             kp_error(ks,
  297.             "cannot stringify event str in invalid context\n");
  298.             return niltv;
  299.         }

  300.         ts = kp_event_stringify(ks);
  301.         if (!ts)
  302.             return niltv;

  303.         return tab_getstr(t, rawtsvalue(key));
  304.     } else if (!is_nil(key)) {
  305.         ktap_node_t *n;
  306. genlookup:
  307.         n = hashkey(t, key);
  308.         do {
  309.             if (kp_obj_equal(&n->key, key))
  310.                 return &n->val;
  311.         } while ((n = n->next));
  312.     }
  313.     return niltv;
  314. }

  315. void kp_tab_get(ktap_state_t *ks, ktap_tab_t *t, const ktap_val_t *key,
  316.         ktap_val_t *val)
  317. {
  318.     unsigned long flags;

  319.     tab_lock(t);
  320.     set_obj(val, tab_get(ks, t, key));
  321.     tab_unlock(t);
  322. }

  323. /* -- Table setters ------------------------------------------------------- */

  324. /* Insert new key. Use Brent's variation to optimize the chain length. */
  325. static ktap_val_t *kp_tab_newkey(ktap_state_t *ks, ktap_tab_t *t,
  326.                  const ktap_val_t *key)
  327. {
  328.     ktap_node_t *n = hashkey(t, key);

  329.     if (!is_nil(&n->val) || t->hmask == 0) {
  330.         ktap_node_t *nodebase = t->node;
  331.         ktap_node_t *collide, *freenode = t->freetop;

  332.         kp_assert(freenode >= nodebase &&
  333.               freenode <= nodebase+t->hmask+1);
  334.         do {
  335.             if (freenode == nodebase) {  /* No free node found? */
  336.                 //kp_error(ks, LJ_ERR_TABOV);
  337.                 kp_error(ks, "table overflow\n");
  338.                 return NULL;
  339.             }
  340.         } while (!is_nil(&(--freenode)->key));

  341.         t->freetop = freenode;
  342.         collide = hashkey(t, &n->key);
  343.         if (collide != n) {  /* Colliding node not the main node? */
  344.             while (collide->next != n)
  345.                 /* Find predecessor. */
  346.                 collide = collide->next;
  347.             collide->next = freenode;  /* Relink chain. */
  348.              /* Copy colliding node into free node and
  349.              * free main node. */
  350.             freenode->val = n->val;
  351.             freenode->key = n->key;
  352.             freenode->next = n->next;
  353.             n->next = NULL;
  354.             set_nil(&n->val);
  355.             /* Rechain pseudo-resurrected string keys with
  356.              * colliding hashes. */
  357.             while (freenode->next) {
  358.                 ktap_node_t *nn = freenode->next;
  359.                 if (is_string(&nn->key) && !is_nil(&nn->val) &&
  360.                     hashstr(t, rawtsvalue(&nn->key)) == n) {
  361.                     freenode->next = nn->next;
  362.                     nn->next = n->next;
  363.                     n->next = nn;
  364.                 } else {
  365.                     freenode = nn;
  366.                 }
  367.             }
  368.         } else/* Otherwise use free node. */
  369.             freenode->next = n->next;  /* Insert into chain. */
  370.             n->next = freenode;
  371.             n = freenode;
  372.         }
  373.     }
  374.     set_obj(&n->key, key);
  375.     t->hnum++;
  376.     return &n->val;
  377. }

  378. static ktap_val_t *tab_setinth(ktap_state_t *ks, ktap_tab_t *t, uint32_t key)
  379. {
  380.     ktap_val_t k;
  381.     ktap_node_t *n;

  382.     set_number(&k, (ktap_number)key);
  383.     n = hashnum(t, &k);
  384.     do {
  385.         if (is_number(&n->key) && nvalue(&n->key) == key)
  386.             return &n->val;
  387.     } while ((n = n->next));
  388.     return kp_tab_newkey(ks, t, &k);
  389. }

  390. static __always_inline
  391. ktap_val_t *tab_setint(ktap_state_t *ks, ktap_tab_t *t, uint32_t key)
  392. {
  393.     return ((key < t->asize) ? arrayslot(t, key) :
  394.                    tab_setinth(ks, t, key));
  395. }

  396. void kp_tab_setint(ktap_state_t *ks, ktap_tab_t *t,
  397.            uint32_t key, const ktap_val_t *val)
  398. {
  399.     ktap_val_t *v;
  400.     unsigned long flags;

  401.     tab_lock(t);
  402.     v = tab_setint(ks, t, key);
  403.     if (likely(v))
  404.         set_obj(v, val);
  405.     tab_unlock(t);
  406. }

  407. void kp_tab_incrint(ktap_state_t *ks, ktap_tab_t *t, uint32_t key,
  408.             ktap_number n)
  409. {
  410.     ktap_val_t *v;
  411.     unsigned long flags;

  412.     tab_lock(t);
  413.     v = tab_setint(ks, t, key);
  414.     if (unlikely(!v))
  415.         goto out;

  416.     if (likely(is_number(v)))
  417.         set_number(v, nvalue(v) + n);
  418.     else if (is_nil(v))
  419.         set_number(v, n);
  420.     else
  421.         kp_error(ks, "use '+=' operator on non-number value\n");

  422. out:
  423.     tab_unlock(t);
  424. }

  425. static ktap_val_t *tab_setstr(ktap_state_t *ks, ktap_tab_t *t,
  426.                   const ktap_str_t *key)
  427. {
  428.     ktap_val_t k;
  429.     ktap_node_t *n = hashstr(t, key);
  430.     do {
  431.         if (is_string(&n->key) && rawtsvalue(&n->key) == key)
  432.             return &n->val;
  433.     } while ((n = n->next));
  434.     set_string(&k, key);
  435.     return kp_tab_newkey(ks, t, &k);
  436. }

  437. void kp_tab_setstr(ktap_state_t *ks, ktap_tab_t *t, const ktap_str_t *key,
  438.            const ktap_val_t *val)
  439. {
  440.     ktap_val_t *v;
  441.     unsigned long flags;

  442.     tab_lock(t);
  443.     v = tab_setstr(ks, t, key);
  444.     if (likely(v))
  445.         set_obj(v, val);
  446.     tab_unlock(t);
  447. }

  448. void kp_tab_incrstr(ktap_state_t *ks, ktap_tab_t *t, const ktap_str_t *key,
  449.             ktap_number n)
  450. {
  451.     ktap_val_t *v;
  452.     unsigned long flags;

  453.     tab_lock(t);
  454.     v = tab_setstr(ks, t, key);
  455.     if (unlikely(!v))
  456.         goto out;

  457.     if (likely(is_number(v)))
  458.         set_number(v, nvalue(v) + n);
  459.     else if (is_nil(v))
  460.         set_number(v, n);
  461.     else
  462.         kp_error(ks, "use '+=' operator on non-number value\n");
  463. out:
  464.     tab_unlock(t);
  465. }

  466. static ktap_val_t *tab_set(ktap_state_t *ks, ktap_tab_t *t,
  467.                const ktap_val_t *key)
  468. {
  469.     ktap_node_t *n;

  470.     if (is_string(key)) {
  471.         return tab_setstr(ks, t, rawtsvalue(key));
  472.     } else if (is_number(key)) {
  473.         ktap_number nk = nvalue(key);
  474.         uint32_t k = (ktap_number)nk;
  475.         if (nk == (ktap_number)k)
  476.             return tab_setint(ks, t, k);
  477.     } else if (itype(key) == KTAP_TKSTACK) {
  478.         /* change stack into string */
  479.         ktap_str_t *bt = kp_obj_kstack2str(ks, key->val.stack.depth,
  480.                                key->val.stack.skip);
  481.         if (!bt)
  482.             return NULL;
  483.         return tab_setstr(ks, t, bt);
  484.     } else if (is_eventstr(key)) {
  485.         const ktap_str_t *ts;

  486.         if (!ks->current_event) {
  487.             kp_error(ks,
  488.             "cannot stringify event str in invalid context\n");
  489.             return NULL;
  490.         }

  491.         ts = kp_event_stringify(ks);
  492.         if (!ts)
  493.             return NULL;

  494.         return tab_setstr(ks, t, ts);
  495.         /* Else use the generic lookup. */
  496.     } else if (is_nil(key)) {
  497.         //kp_error(ks, LJ_ERR_NILIDX);
  498.         kp_error(ks, "table nil index\n");
  499.         return NULL;
  500.     }
  501.     n = hashkey(t, key);
  502.     do {
  503.         if (kp_obj_equal(&n->key, key))
  504.             return &n->val;
  505.     } while ((n = n->next));
  506.     return kp_tab_newkey(ks, t, key);
  507. }

  508. void kp_tab_set(ktap_state_t *ks, ktap_tab_t *t,
  509.         const ktap_val_t *key, const ktap_val_t *val)
  510. {
  511.     ktap_val_t *v;
  512.     unsigned long flags;

  513.     tab_lock(t);
  514.     v = tab_set(ks, t, key);
  515.     if (likely(v))
  516.         set_obj(v, val);
  517.     tab_unlock(t);
  518. }

  519. void kp_tab_incr(ktap_state_t *ks, ktap_tab_t *t, ktap_val_t *key,
  520.          ktap_number n)
  521. {
  522.     ktap_val_t *v;
  523.     unsigned long flags;

  524.     tab_lock(t);
  525.     v = tab_set(ks, t, key);
  526.     if (unlikely(!v))
  527.         goto out;

  528.     if (likely(is_number(v)))
  529.         set_number(v, nvalue(v) + n);
  530.     else if (is_nil(v))
  531.         set_number(v, n);
  532.     else
  533.         kp_error(ks, "use '+=' operator on non-number value\n");
  534. out:
  535.     tab_unlock(t);
  536. }


  537. /* -- Table traversal ----------------------------------------------------- */

  538. /* Get the traversal index of a key. */
  539. static uint32_t keyindex(ktap_state_t *ks, ktap_tab_t *t,
  540.              const ktap_val_t *key)
  541. {
  542.     if (is_number(key)) {
  543.         ktap_number nk = nvalue(key);
  544.         uint32_t k = (uint32_t)nk;
  545.         /* Array key indexes: [0..t->asize-1] */
  546.         if ((uint32_t)k < t->asize && nk == (ktap_number)k)
  547.             return (uint32_t)k;
  548.     }

  549.     if (!is_nil(key)) {
  550.         ktap_node_t *n = hashkey(t, key);
  551.         do {
  552.             if (kp_obj_equal(&n->key, key))
  553.                 return t->asize + (uint32_t)(n - (t->node));
  554.             /* Hash key indexes: [t->asize..t->asize+t->nmask] */
  555.         } while ((n = n->next));
  556.         //kp_err_msg(ks, LJ_ERR_NEXTIDX);
  557.         kp_error(ks, "table next index\n");
  558.         return 0/* unreachable */
  559.     }
  560.     return ~0u/* A nil key starts the traversal. */
  561. }

  562. /* Advance to the next step in a table traversal. */
  563. int kp_tab_next(ktap_state_t *ks, ktap_tab_t *t, ktap_val_t *key)
  564. {
  565.     unsigned long flags;
  566.     uint32_t i;

  567.     tab_lock(t);
  568.     i = keyindex(ks, t, key);  /* Find predecessor key index. */

  569.     /* First traverse the array keys. */
  570.     for (i++; i < t->asize; i++)
  571.          if (!is_nil(arrayslot(t, i))) {
  572.             set_number(key, i);
  573.             set_obj(key + 1, arrayslot(t, i));
  574.             tab_unlock(t);
  575.             return 1;
  576.         }
  577.     /* Then traverse the hash keys. */
  578.     for (i -= t->asize; i <= t->hmask; i++) {
  579.         ktap_node_t *n = &t->node[i];
  580.         if (!is_nil(&n->val)) {
  581.             set_obj(key, &n->key);
  582.             set_obj(key + 1, &n->val);
  583.             tab_unlock(t);
  584.             return 1;
  585.         }
  586.     }
  587.     tab_unlock(t);
  588.     return 0/* End of traversal. */
  589. }

  590. /* -- Table length calculation -------------------------------------------- */

  591. int kp_tab_len(ktap_state_t *ks, ktap_tab_t *t)
  592. {
  593.     unsigned long flags;
  594.     int i, len = 0;

  595.     tab_lock(t);
  596.     for (i = 0; i < t->asize; i++) {
  597.         ktap_val_t *v = &t->array[i];

  598.         if (is_nil(v))
  599.             continue;
  600.         len++;
  601.     }

  602.     for (i = 0; i <= t->hmask; i++) {
  603.         ktap_node_t *n = &t->node[i];

  604.         if (is_nil(&n->key))
  605.             continue;

  606.         len++;
  607.     }
  608.     tab_unlock(t);
  609.     return len;
  610. }

  611. static void string_convert(char *output, const char *input)
  612. {
  613.     if (strlen(input) > 32) {
  614.         strncpy(output, input, 32-4);
  615.         memset(output + 32-4, '.', 3);
  616.     } else
  617.         memcpy(output, input, strlen(input));
  618. }

  619. typedef struct ktap_node2 {
  620.     ktap_val_t key;
  621.     ktap_val_t val;
  622. } ktap_node2_t;

  623. static int hist_record_cmp(const void *i, const void *j)
  624. {
  625.     ktap_number n1 = nvalue(&((const ktap_node2_t *)i)->val);
  626.     ktap_number n2 = nvalue(&((const ktap_node2_t *)j)->val);

  627.     if (n1 == n2)
  628.         return 0;
  629.     else if (n1 < n2)
  630.         return 1;
  631.     else
  632.         return -1;
  633. }

  634. /* todo: make histdump to be faster, just need to sort n entries, not all */

  635. /* print_hist: key should be number/string/ip, value must be number */
  636. static void tab_histdump(ktap_state_t *ks, ktap_tab_t *t, int shownums)
  637. {
  638.     long start_time, delta_time;
  639.     uint32_t i, asize = t->asize;
  640.     ktap_val_t *array = t->array;
  641.     uint32_t hmask = t->hmask;
  642.     ktap_node_t *node = t->node;
  643.     ktap_node2_t *sort_mem;
  644.     char dist_str[39];
  645.     int total = 0, sum = 0;

  646.     start_time = gettimeofday_ns();

  647.     sort_mem = kmalloc((t->asize + t->hnum) * sizeof(ktap_node2_t),
  648.                 GFP_KERNEL);
  649.     if (!sort_mem)
  650.         return;

  651.     /* copy all values in table into sort_mem. */
  652.     for (i = 0; i < asize; i++) {
  653.         ktap_val_t *val = &array[i];
  654.         if (is_nil(val))
  655.             continue;

  656.         if (!is_number(val)) {
  657.             kp_error(ks, "print_hist only can print number\n");
  658.             goto out;
  659.         }

  660.         set_number(&sort_mem[total].key, i);
  661.         set_obj(&sort_mem[total].val, val);
  662.         sum += nvalue(val);
  663.         total++;
  664.     }

  665.     for (i = 0; i <= hmask; i++) {
  666.         ktap_node_t *n = &node[i];
  667.         ktap_val_t *val = &n->val;

  668.         if (is_nil(val))
  669.             continue;

  670.         if (!is_number(val)) {
  671.             kp_error(ks, "print_hist only can print number\n");
  672.             goto out;
  673.         }

  674.         set_obj(&sort_mem[total].key, &n->key);
  675.         set_obj(&sort_mem[total].val, val);
  676.         sum += nvalue(val);
  677.         total++;
  678.     }

  679.     /* sort */
  680.     sort(sort_mem, total, sizeof(ktap_node2_t), hist_record_cmp, NULL);

  681.     dist_str[sizeof(dist_str) - 1] = '\0';

  682.     for (i = 0; i < total; i++) {
  683.         ktap_val_t *key = &sort_mem[i].key;
  684.         ktap_number num = nvalue(&sort_mem[i].val);
  685.         int ratio;

  686.         if (!--shownums)
  687.             break;

  688.         memset(dist_str, ' ', sizeof(dist_str) - 1);
  689.         ratio = (num * (sizeof(dist_str) - 1)) / sum;
  690.         memset(dist_str, '@', ratio);

  691.         if (is_string(key)) {
  692.             //char buf[32] = {0};

  693.             //string_convert(buf, svalue(key));
  694.             if (rawtsvalue(key)->len > 32) {
  695.                 kp_puts(ks, svalue(key));
  696.                 kp_printf(ks, "%s\n%d\n\n", dist_str, num);
  697.             } else {
  698.                 kp_printf(ks, "%31s |%s%-7d\n", svalue(key),
  699.                                 dist_str, num);
  700.             }
  701.         } else if (is_number(key)) {
  702.             kp_printf(ks, "%31d |%s%-7d\n", nvalue(key),
  703.                         dist_str, num);
  704.         } else if (is_kip(key)) {
  705.             char str[KSYM_SYMBOL_LEN];
  706.             char buf[32] = {0};

  707.             SPRINT_SYMBOL(str, nvalue(key));
  708.             string_convert(buf, str);
  709.             kp_printf(ks, "%31s |%s%-7d\n", buf, dist_str, num);
  710.         }
  711.     }

  712.     if (!shownums && total)
  713.         kp_printf(ks, "%31s |\n", "...");

  714. out:
  715.     kfree(sort_mem);

  716.     delta_time = (gettimeofday_ns() - start_time) / NSEC_PER_USEC;
  717.     kp_verbose_printf(ks, "tab_histdump time: %d (us)\n", delta_time);
  718. }

  719. #define DISTRIBUTION_STR "------------- Distribution -------------"
  720. void kp_tab_print_hist(ktap_state_t *ks, ktap_tab_t *t, int n)
  721. {
  722.     kp_printf(ks, "%31s%s%s\n", "value ", DISTRIBUTION_STR, " count");
  723.     tab_histdump(ks, t, n);
  724. }