Print this page
        
*** 116,126 ****
   *         - per vnode (entity->vme_vnode_hash)
   *         - per shared amp (entity->vme_amp_hash)
   *      For accurate counting of map-shared and COW-shared pages.
   *
   *    - visited private anons (refcnt > 1) for each collective.
!  *      (entity->vme_anon)
   *      For accurate counting of COW-shared pages.
   *
   * The common accounting structure is the vmu_entity_t, which represents
   * collectives:
   *
--- 116,126 ----
   *         - per vnode (entity->vme_vnode_hash)
   *         - per shared amp (entity->vme_amp_hash)
   *      For accurate counting of map-shared and COW-shared pages.
   *
   *    - visited private anons (refcnt > 1) for each collective.
!  *      (entity->vme_anon_hash)
   *      For accurate counting of COW-shared pages.
   *
   * The common accounting structure is the vmu_entity_t, which represents
   * collectives:
   *
*** 154,164 ****
  #include <sys/systm.h>
  #include <sys/var.h>
  #include <sys/vm_usage.h>
  #include <sys/zone.h>
  #include <sys/sunddi.h>
- #include <sys/sysmacros.h>
  #include <sys/avl.h>
  #include <vm/anon.h>
  #include <vm/as.h>
  #include <vm/seg_vn.h>
  #include <vm/seg_spt.h>
--- 154,163 ----
*** 202,219 ****
          short           vmo_type;
          avl_tree_t      vmo_bounds;
  } vmu_object_t;
  
  /*
-  * Node for tree of visited COW anons.
-  */
- typedef struct vmu_anon {
-         avl_node_t vma_node;
-         uintptr_t vma_addr;
- } vmu_anon_t;
- 
- /*
   * Entity by which to count results.
   *
   * The entity structure keeps the current rss/swap counts for each entity
   * (zone, project, etc), and hashes of vm structures that have already
   * been visited for the entity.
--- 201,210 ----
*** 232,242 ****
  typedef struct vmu_entity {
          struct vmu_entity *vme_next;
          struct vmu_entity *vme_next_calc;
          mod_hash_t      *vme_vnode_hash; /* vnodes visited for entity */
          mod_hash_t      *vme_amp_hash;   /* shared amps visited for entity */
!         avl_tree_t      vme_anon;        /* COW anons visited for entity */
          vmusage_t       vme_result;      /* identifies entity and results */
  } vmu_entity_t;
  
  /*
   * Hash of entities visited within a zone, and an entity for the zone
--- 223,233 ----
  typedef struct vmu_entity {
          struct vmu_entity *vme_next;
          struct vmu_entity *vme_next_calc;
          mod_hash_t      *vme_vnode_hash; /* vnodes visited for entity */
          mod_hash_t      *vme_amp_hash;   /* shared amps visited for entity */
!         mod_hash_t      *vme_anon_hash;  /* COW anons visited for entity */
          vmusage_t       vme_result;      /* identifies entity and results */
  } vmu_entity_t;
  
  /*
   * Hash of entities visited within a zone, and an entity for the zone
*** 335,361 ****
  
          return (1);
  }
  
  /*
-  * Comparison routine for our AVL tree of anon structures.
-  */
- static int
- vmu_anon_cmp(const void *lhs, const void *rhs)
- {
-         const vmu_anon_t *l = lhs, *r = rhs;
- 
-         if (l->vma_addr == r->vma_addr)
-                 return (0);
- 
-         if (l->vma_addr < r->vma_addr)
-                 return (-1);
- 
-         return (1);
- }
- 
- /*
   * Save a bound on the free list.
   */
  static void
  vmu_free_bound(vmu_bound_t *bound)
  {
--- 326,335 ----
*** 391,413 ****
   */
  static void
  vmu_free_entity(mod_hash_val_t val)
  {
          vmu_entity_t *entity = (vmu_entity_t *)val;
-         vmu_anon_t *anon;
-         void *cookie = NULL;
  
          if (entity->vme_vnode_hash != NULL)
                  i_mod_hash_clear_nosync(entity->vme_vnode_hash);
          if (entity->vme_amp_hash != NULL)
                  i_mod_hash_clear_nosync(entity->vme_amp_hash);
  
-         while ((anon = avl_destroy_nodes(&entity->vme_anon, &cookie)) != NULL)
-                 kmem_free(anon, sizeof (vmu_anon_t));
- 
-         avl_destroy(&entity->vme_anon);
- 
          entity->vme_next = vmu_data.vmu_free_entities;
          vmu_data.vmu_free_entities = entity;
  }
  
  /*
--- 365,382 ----
   */
  static void
  vmu_free_entity(mod_hash_val_t val)
  {
          vmu_entity_t *entity = (vmu_entity_t *)val;
  
          if (entity->vme_vnode_hash != NULL)
                  i_mod_hash_clear_nosync(entity->vme_vnode_hash);
          if (entity->vme_amp_hash != NULL)
                  i_mod_hash_clear_nosync(entity->vme_amp_hash);
+         if (entity->vme_anon_hash != NULL)
+                 i_mod_hash_clear_nosync(entity->vme_anon_hash);
  
          entity->vme_next = vmu_data.vmu_free_entities;
          vmu_data.vmu_free_entities = entity;
  }
  
  /*
*** 518,532 ****
          if (entity->vme_amp_hash == NULL)
                  entity->vme_amp_hash = mod_hash_create_ptrhash(
                      "vmusage amp hash", VMUSAGE_HASH_SIZE, vmu_free_object,
                      sizeof (struct anon_map));
  
!         VERIFY(avl_first(&entity->vme_anon) == NULL);
  
-         avl_create(&entity->vme_anon, vmu_anon_cmp, sizeof (struct vmu_anon),
-             offsetof(struct vmu_anon, vma_node));
- 
          entity->vme_next = vmu_data.vmu_entities;
          vmu_data.vmu_entities = entity;
          vmu_data.vmu_nentities++;
  
          return (entity);
--- 487,501 ----
          if (entity->vme_amp_hash == NULL)
                  entity->vme_amp_hash = mod_hash_create_ptrhash(
                      "vmusage amp hash", VMUSAGE_HASH_SIZE, vmu_free_object,
                      sizeof (struct anon_map));
  
!         if (entity->vme_anon_hash == NULL)
!                 entity->vme_anon_hash = mod_hash_create_ptrhash(
!                     "vmusage anon hash", VMUSAGE_HASH_SIZE,
!                     mod_hash_null_valdtor, sizeof (struct anon));
  
          entity->vme_next = vmu_data.vmu_entities;
          vmu_data.vmu_entities = entity;
          vmu_data.vmu_nentities++;
  
          return (entity);
*** 647,669 ****
          }
          return (object);
  }
  
  static int
! vmu_find_insert_anon(vmu_entity_t *entity, void *key)
  {
!         vmu_anon_t anon, *ap;
  
!         anon.vma_addr = (uintptr_t)key;
  
!         if (avl_find(&entity->vme_anon, &anon, NULL) != NULL)
                  return (0);
  
!         ap = kmem_alloc(sizeof (vmu_anon_t), KM_SLEEP);
!         ap->vma_addr = (uintptr_t)key;
  
!         avl_add(&entity->vme_anon, ap);
  
          return (1);
  }
  
  static vmu_entity_t *
--- 616,640 ----
          }
          return (object);
  }
  
  static int
! vmu_find_insert_anon(mod_hash_t *hash, caddr_t key)
  {
!         int ret;
!         caddr_t val;
  
!         ret = i_mod_hash_find_nosync(hash, (mod_hash_key_t)key,
!             (mod_hash_val_t *)&val);
  
!         if (ret == 0)
                  return (0);
  
!         ret = i_mod_hash_insert_nosync(hash, (mod_hash_key_t)key,
!             (mod_hash_val_t)key, (mod_hash_hndl_t)0);
  
!         ASSERT(ret == 0);
  
          return (1);
  }
  
  static vmu_entity_t *
*** 1371,1381 ****
                                  result = &entity->vme_result;
                                  /*
                                   * Track COW anons per entity so
                                   * they are not double counted.
                                   */
!                                 if (vmu_find_insert_anon(entity, ap) == 0)
                                          continue;
  
                                  result->vmu_rss_all += (pgcnt << PAGESHIFT);
                                  result->vmu_rss_private +=
                                      (pgcnt << PAGESHIFT);
--- 1342,1353 ----
                                  result = &entity->vme_result;
                                  /*
                                   * Track COW anons per entity so
                                   * they are not double counted.
                                   */
!                                 if (vmu_find_insert_anon(entity->vme_anon_hash,
!                                     (caddr_t)ap) == 0)
                                          continue;
  
                                  result->vmu_rss_all += (pgcnt << PAGESHIFT);
                                  result->vmu_rss_private +=
                                      (pgcnt << PAGESHIFT);
*** 1645,1655 ****
                      vmu_data.vmu_free_entities->vme_next;
                  if (te->vme_vnode_hash != NULL)
                          mod_hash_destroy_hash(te->vme_vnode_hash);
                  if (te->vme_amp_hash != NULL)
                          mod_hash_destroy_hash(te->vme_amp_hash);
!                 VERIFY(avl_first(&te->vme_anon) == NULL);
                  kmem_free(te, sizeof (vmu_entity_t));
          }
          while (vmu_data.vmu_free_zones != NULL) {
                  tz = vmu_data.vmu_free_zones;
                  vmu_data.vmu_free_zones =
--- 1617,1628 ----
                      vmu_data.vmu_free_entities->vme_next;
                  if (te->vme_vnode_hash != NULL)
                          mod_hash_destroy_hash(te->vme_vnode_hash);
                  if (te->vme_amp_hash != NULL)
                          mod_hash_destroy_hash(te->vme_amp_hash);
!                 if (te->vme_anon_hash != NULL)
!                         mod_hash_destroy_hash(te->vme_anon_hash);
                  kmem_free(te, sizeof (vmu_entity_t));
          }
          while (vmu_data.vmu_free_zones != NULL) {
                  tz = vmu_data.vmu_free_zones;
                  vmu_data.vmu_free_zones =