Print this page


Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/vm/vm_usage.c
          +++ new/usr/src/uts/common/vm/vm_usage.c
↓ open down ↓ 110 lines elided ↑ open up ↑
 111  111   *    - incore/not-incore page ranges for all shared amps.
 112  112   *      (vmu_data.vmu_all_amps_hash)
 113  113   *      This eliminates looking up the same page more than once.
 114  114   *
 115  115   *    - visited page ranges for each collective.
 116  116   *         - per vnode (entity->vme_vnode_hash)
 117  117   *         - per shared amp (entity->vme_amp_hash)
 118  118   *      For accurate counting of map-shared and COW-shared pages.
 119  119   *
 120  120   *    - visited private anons (refcnt > 1) for each collective.
 121      - *      (entity->vme_anon)
      121 + *      (entity->vme_anon_hash)
 122  122   *      For accurate counting of COW-shared pages.
 123  123   *
 124  124   * The common accounting structure is the vmu_entity_t, which represents
 125  125   * collectives:
 126  126   *
 127  127   *    - A zone.
 128  128   *    - A project, task, or user within a zone.
 129  129   *    - The entire system (vmu_data.vmu_system).
 130  130   *    - Each collapsed (col) project and user.  This means a given projid or
 131  131   *      uid, regardless of which zone the process is in.  For instance,
↓ open down ↓ 17 lines elided ↑ open up ↑
 149  149  #include <sys/modhash.h>
 150  150  #include <sys/modhash_impl.h>
 151  151  #include <sys/shm.h>
 152  152  #include <sys/swap.h>
 153  153  #include <sys/synch.h>
 154  154  #include <sys/systm.h>
 155  155  #include <sys/var.h>
 156  156  #include <sys/vm_usage.h>
 157  157  #include <sys/zone.h>
 158  158  #include <sys/sunddi.h>
 159      -#include <sys/sysmacros.h>
 160  159  #include <sys/avl.h>
 161  160  #include <vm/anon.h>
 162  161  #include <vm/as.h>
 163  162  #include <vm/seg_vn.h>
 164  163  #include <vm/seg_spt.h>
 165  164  
 166  165  #define VMUSAGE_HASH_SIZE               512
 167  166  
 168  167  #define VMUSAGE_TYPE_VNODE              1
 169  168  #define VMUSAGE_TYPE_AMP                2
↓ open down ↓ 27 lines elided ↑ open up ↑
 197  196   * bounds for vnode/amp.
 198  197   */
 199  198  typedef struct vmu_object {
 200  199          struct vmu_object       *vmo_next;      /* free list */
 201  200          caddr_t         vmo_key;
 202  201          short           vmo_type;
 203  202          avl_tree_t      vmo_bounds;
 204  203  } vmu_object_t;
 205  204  
 206  205  /*
 207      - * Node for tree of visited COW anons.
 208      - */
 209      -typedef struct vmu_anon {
 210      -        avl_node_t vma_node;
 211      -        uintptr_t vma_addr;
 212      -} vmu_anon_t;
 213      -
 214      -/*
 215  206   * Entity by which to count results.
 216  207   *
 217  208   * The entity structure keeps the current rss/swap counts for each entity
 218  209   * (zone, project, etc), and hashes of vm structures that have already
 219  210   * been visited for the entity.
 220  211   *
 221  212   * vme_next:    links the list of all entities currently being counted by
 222  213   *              vmu_calculate().
 223  214   *
 224  215   * vme_next_calc: links the list of entities related to the current process
↓ open down ↓ 2 lines elided ↑ open up ↑
 227  218   * vmu_calculate_proc() walks all processes.  For each process, it makes a
 228  219   * list of the entities related to that process using vme_next_calc.  This
 229  220   * list changes each time vmu_calculate_proc() is called.
 230  221   *
 231  222   */
 232  223  typedef struct vmu_entity {
 233  224          struct vmu_entity *vme_next;
 234  225          struct vmu_entity *vme_next_calc;
 235  226          mod_hash_t      *vme_vnode_hash; /* vnodes visited for entity */
 236  227          mod_hash_t      *vme_amp_hash;   /* shared amps visited for entity */
 237      -        avl_tree_t      vme_anon;        /* COW anons visited for entity */
      228 +        mod_hash_t      *vme_anon_hash;  /* COW anons visited for entity */
 238  229          vmusage_t       vme_result;      /* identifies entity and results */
 239  230  } vmu_entity_t;
 240  231  
 241  232  /*
 242  233   * Hash of entities visited within a zone, and an entity for the zone
 243  234   * itself.
 244  235   */
 245  236  typedef struct vmu_zone {
 246  237          struct vmu_zone *vmz_next;      /* free list */
 247  238          id_t            vmz_id;
↓ open down ↓ 82 lines elided ↑ open up ↑
 330  321                  return (0);
 331  322          }
 332  323          if (bound1->vmb_start < bound2->vmb_start) {
 333  324                  return (-1);
 334  325          }
 335  326  
 336  327          return (1);
 337  328  }
 338  329  
 339  330  /*
 340      - * Comparison routine for our AVL tree of anon structures.
 341      - */
 342      -static int
 343      -vmu_anon_cmp(const void *lhs, const void *rhs)
 344      -{
 345      -        const vmu_anon_t *l = lhs, *r = rhs;
 346      -
 347      -        if (l->vma_addr == r->vma_addr)
 348      -                return (0);
 349      -
 350      -        if (l->vma_addr < r->vma_addr)
 351      -                return (-1);
 352      -
 353      -        return (1);
 354      -}
 355      -
 356      -/*
 357  331   * Save a bound on the free list.
 358  332   */
 359  333  static void
 360  334  vmu_free_bound(vmu_bound_t *bound)
 361  335  {
 362  336          bound->vmb_next = vmu_data.vmu_free_bounds;
 363  337          bound->vmb_start = 0;
 364  338          bound->vmb_end = 0;
 365  339          bound->vmb_type = 0;
 366  340          vmu_data.vmu_free_bounds = bound;
↓ open down ↓ 19 lines elided ↑ open up ↑
 386  360          vmu_data.vmu_free_objects = obj;
 387  361  }
 388  362  
 389  363  /*
 390  364   * Free an entity, and hashes of visited objects for that entity.
 391  365   */
 392  366  static void
 393  367  vmu_free_entity(mod_hash_val_t val)
 394  368  {
 395  369          vmu_entity_t *entity = (vmu_entity_t *)val;
 396      -        vmu_anon_t *anon;
 397      -        void *cookie = NULL;
 398  370  
 399  371          if (entity->vme_vnode_hash != NULL)
 400  372                  i_mod_hash_clear_nosync(entity->vme_vnode_hash);
 401  373          if (entity->vme_amp_hash != NULL)
 402  374                  i_mod_hash_clear_nosync(entity->vme_amp_hash);
      375 +        if (entity->vme_anon_hash != NULL)
      376 +                i_mod_hash_clear_nosync(entity->vme_anon_hash);
 403  377  
 404      -        while ((anon = avl_destroy_nodes(&entity->vme_anon, &cookie)) != NULL)
 405      -                kmem_free(anon, sizeof (vmu_anon_t));
 406      -
 407      -        avl_destroy(&entity->vme_anon);
 408      -
 409  378          entity->vme_next = vmu_data.vmu_free_entities;
 410  379          vmu_data.vmu_free_entities = entity;
 411  380  }
 412  381  
 413  382  /*
 414  383   * Free zone entity, and all hashes of entities inside that zone,
 415  384   * which are projects, tasks, and users.
 416  385   */
 417  386  static void
 418  387  vmu_free_zone(mod_hash_val_t val)
↓ open down ↓ 94 lines elided ↑ open up ↑
 513  482          if (entity->vme_vnode_hash == NULL)
 514  483                  entity->vme_vnode_hash = mod_hash_create_ptrhash(
 515  484                      "vmusage vnode hash", VMUSAGE_HASH_SIZE, vmu_free_object,
 516  485                      sizeof (vnode_t));
 517  486  
 518  487          if (entity->vme_amp_hash == NULL)
 519  488                  entity->vme_amp_hash = mod_hash_create_ptrhash(
 520  489                      "vmusage amp hash", VMUSAGE_HASH_SIZE, vmu_free_object,
 521  490                      sizeof (struct anon_map));
 522  491  
 523      -        VERIFY(avl_first(&entity->vme_anon) == NULL);
      492 +        if (entity->vme_anon_hash == NULL)
      493 +                entity->vme_anon_hash = mod_hash_create_ptrhash(
      494 +                    "vmusage anon hash", VMUSAGE_HASH_SIZE,
      495 +                    mod_hash_null_valdtor, sizeof (struct anon));
 524  496  
 525      -        avl_create(&entity->vme_anon, vmu_anon_cmp, sizeof (struct vmu_anon),
 526      -            offsetof(struct vmu_anon, vma_node));
 527      -
 528  497          entity->vme_next = vmu_data.vmu_entities;
 529  498          vmu_data.vmu_entities = entity;
 530  499          vmu_data.vmu_nentities++;
 531  500  
 532  501          return (entity);
 533  502  }
 534  503  
 535  504  /*
 536  505   * Allocate a zone entity, and hashes for tracking visited vm objects
 537  506   * for projects, tasks, and users within that zone.
↓ open down ↓ 104 lines elided ↑ open up ↑
 642  611          if (ret != 0) {
 643  612                  object = vmu_alloc_object(key, type);
 644  613                  ret = i_mod_hash_insert_nosync(hash, (mod_hash_key_t)key,
 645  614                      (mod_hash_val_t)object, (mod_hash_hndl_t)0);
 646  615                  ASSERT(ret == 0);
 647  616          }
 648  617          return (object);
 649  618  }
 650  619  
 651  620  static int
 652      -vmu_find_insert_anon(vmu_entity_t *entity, void *key)
      621 +vmu_find_insert_anon(mod_hash_t *hash, caddr_t key)
 653  622  {
 654      -        vmu_anon_t anon, *ap;
      623 +        int ret;
      624 +        caddr_t val;
 655  625  
 656      -        anon.vma_addr = (uintptr_t)key;
      626 +        ret = i_mod_hash_find_nosync(hash, (mod_hash_key_t)key,
      627 +            (mod_hash_val_t *)&val);
 657  628  
 658      -        if (avl_find(&entity->vme_anon, &anon, NULL) != NULL)
      629 +        if (ret == 0)
 659  630                  return (0);
 660  631  
 661      -        ap = kmem_alloc(sizeof (vmu_anon_t), KM_SLEEP);
 662      -        ap->vma_addr = (uintptr_t)key;
      632 +        ret = i_mod_hash_insert_nosync(hash, (mod_hash_key_t)key,
      633 +            (mod_hash_val_t)key, (mod_hash_hndl_t)0);
 663  634  
 664      -        avl_add(&entity->vme_anon, ap);
      635 +        ASSERT(ret == 0);
 665  636  
 666  637          return (1);
 667  638  }
 668  639  
 669  640  static vmu_entity_t *
 670  641  vmu_find_insert_entity(mod_hash_t *hash, id_t id, uint_t type, id_t zoneid)
 671  642  {
 672  643          int ret;
 673  644          vmu_entity_t *entity;
 674  645  
↓ open down ↓ 691 lines elided ↑ open up ↑
1366 1337                                  continue;
1367 1338                          }
1368 1339                          for (entity = vmu_entities; entity != NULL;
1369 1340                              entity = entity->vme_next_calc) {
1370 1341  
1371 1342                                  result = &entity->vme_result;
1372 1343                                  /*
1373 1344                                   * Track COW anons per entity so
1374 1345                                   * they are not double counted.
1375 1346                                   */
1376      -                                if (vmu_find_insert_anon(entity, ap) == 0)
     1347 +                                if (vmu_find_insert_anon(entity->vme_anon_hash,
     1348 +                                    (caddr_t)ap) == 0)
1377 1349                                          continue;
1378 1350  
1379 1351                                  result->vmu_rss_all += (pgcnt << PAGESHIFT);
1380 1352                                  result->vmu_rss_private +=
1381 1353                                      (pgcnt << PAGESHIFT);
1382 1354                          }
1383 1355                  }
1384 1356                  ANON_LOCK_EXIT(&private_amp->a_rwlock);
1385 1357          }
1386 1358  
↓ open down ↓ 253 lines elided ↑ open up ↑
1640 1612                  kmem_cache_free(vmu_object_cache, to);
1641 1613          }
1642 1614          while (vmu_data.vmu_free_entities != NULL) {
1643 1615                  te = vmu_data.vmu_free_entities;
1644 1616                  vmu_data.vmu_free_entities =
1645 1617                      vmu_data.vmu_free_entities->vme_next;
1646 1618                  if (te->vme_vnode_hash != NULL)
1647 1619                          mod_hash_destroy_hash(te->vme_vnode_hash);
1648 1620                  if (te->vme_amp_hash != NULL)
1649 1621                          mod_hash_destroy_hash(te->vme_amp_hash);
1650      -                VERIFY(avl_first(&te->vme_anon) == NULL);
     1622 +                if (te->vme_anon_hash != NULL)
     1623 +                        mod_hash_destroy_hash(te->vme_anon_hash);
1651 1624                  kmem_free(te, sizeof (vmu_entity_t));
1652 1625          }
1653 1626          while (vmu_data.vmu_free_zones != NULL) {
1654 1627                  tz = vmu_data.vmu_free_zones;
1655 1628                  vmu_data.vmu_free_zones =
1656 1629                      vmu_data.vmu_free_zones->vmz_next;
1657 1630                  if (tz->vmz_projects_hash != NULL)
1658 1631                          mod_hash_destroy_hash(tz->vmz_projects_hash);
1659 1632                  if (tz->vmz_tasks_hash != NULL)
1660 1633                          mod_hash_destroy_hash(tz->vmz_tasks_hash);
↓ open down ↓ 137 lines elided ↑ open up ↑
1798 1771  vmu_update_zone_rctls(vmu_cache_t *cache)
1799 1772  {
1800 1773          vmusage_t       *rp;
1801 1774          size_t          i = 0;
1802 1775          zone_t          *zp;
1803 1776  
1804 1777          for (rp = cache->vmc_results; i < cache->vmc_nresults; rp++, i++) {
1805 1778                  if (rp->vmu_type == VMUSAGE_ZONE &&
1806 1779                      rp->vmu_zoneid != ALL_ZONES) {
1807 1780                          if ((zp = zone_find_by_id(rp->vmu_zoneid)) != NULL) {
1808      -                                zp->zone_phys_mem = rp->vmu_rss_all;
1809      -                                zone_rele(zp);
     1781 +                                zp->zone_phys_mem = rp->vmu_rss_all;
     1782 +                                zone_rele(zp);
1810 1783                          }
1811 1784                  }
1812 1785          }
1813 1786  }
1814 1787  
1815 1788  /*
1816 1789   * Copy out the cached results to a caller.  Inspect the callers flags
1817 1790   * and zone to determine which cached results should be copied.
1818 1791   */
1819 1792  static int
↓ open down ↓ 500 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX