Whamcloud - gitweb
b=23289 less global lock & atomic for ldlm pool
[fs/lustre-release.git] / lustre / ldlm / ldlm_pool.c
index 08bbec9..9de7e73 100644 (file)
@@ -26,7 +26,7 @@
  * GPL HEADER END
  */
 /*
- * Copyright  2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  */
 /*
  * This controls the speed of reaching LDLM_POOL_MAX_GSP
  * with increasing thread period.
  */
-#define LDLM_POOL_GSP_STEP (4)
+#define LDLM_POOL_GSP_STEP_SHIFT (2)
 
 /*
  * LDLM_POOL_GSP% of all locks is default GP.
  */
 #define LDLM_POOL_MAX_AGE (36000)
 
+/*
+ * The granularity of SLV calculation.
+ */
+#define LDLM_POOL_SLV_SHIFT (10)
+
 #ifdef __KERNEL__
 extern cfs_proc_dir_entry_t *ldlm_ns_proc_dir;
 #endif
 
-#define avg(src, add) \
-        ((src) = ((src) + (add)) / 2)
-
-static inline __u64 dru(__u64 val, __u32 div)
+static inline __u64 dru(__u64 val, __u32 shift, int round_up)
 {
-        __u64 ret = val + (div - 1);
-        do_div(ret, div);
-        return ret;
+        return (val + (round_up ? (1 << shift) - 1 : 0)) >> shift;
 }
 
 static inline __u64 ldlm_pool_slv_max(__u32 L)
@@ -162,7 +162,7 @@ static inline __u64 ldlm_pool_slv_max(__u32 L)
          * Allow to have all locks for 1 client for 10 hrs.
          * Formula is the following: limit * 10h / 1 client.
          */
-        __u64 lim = L *  LDLM_POOL_MAX_AGE / 1;
+        __u64 lim = (__u64)L *  LDLM_POOL_MAX_AGE / 1;
         return lim;
 }
 
@@ -196,18 +196,18 @@ static inline struct ldlm_namespace *ldlm_pl2ns(struct ldlm_pool *pl)
  * Calculates suggested grant_step in % of available locks for passed
  * \a period. This is later used in grant_plan calculations.
  */
-static inline int ldlm_pool_t2gsp(int t)
+static inline int ldlm_pool_t2gsp(unsigned int t)
 {
         /*
-         * This yeilds 1% grant step for anything below LDLM_POOL_GSP_STEP
+         * This yields 1% grant step for anything below LDLM_POOL_GSP_STEP
          * and up to 30% for anything higher than LDLM_POOL_GSP_STEP.
          *
          * How this will affect execution is the following:
          *
-         * - for thread peroid 1s we will have grant_step 1% which good from
+         * - for thread period 1s we will have grant_step 1% which good from
          * pov of taking some load off from server and push it out to clients.
          * This is like that because 1% for grant_step means that server will
-         * not allow clients to get lots of locks inshort period of time and
+         * not allow clients to get lots of locks in short period of time and
          * keep all old locks in their caches. Clients will always have to
          * get some locks back if they want to take some new;
          *
@@ -219,8 +219,8 @@ static inline int ldlm_pool_t2gsp(int t)
          * plan is reached.
          */
         return LDLM_POOL_MAX_GSP -
-                (LDLM_POOL_MAX_GSP - LDLM_POOL_MIN_GSP) /
-                (1 << (t / LDLM_POOL_GSP_STEP));
+                ((LDLM_POOL_MAX_GSP - LDLM_POOL_MIN_GSP) >>
+                 (t >> LDLM_POOL_GSP_STEP_SHIFT));
 }
 
 /**
@@ -228,7 +228,7 @@ static inline int ldlm_pool_t2gsp(int t)
  *
  * \pre ->pl_lock is locked.
  */
-static inline void ldlm_pool_recalc_grant_plan(struct ldlm_pool *pl)
+static void ldlm_pool_recalc_grant_plan(struct ldlm_pool *pl)
 {
         int granted, grant_step, limit;
 
@@ -238,6 +238,9 @@ static inline void ldlm_pool_recalc_grant_plan(struct ldlm_pool *pl)
         grant_step = ldlm_pool_t2gsp(pl->pl_recalc_period);
         grant_step = ((limit - granted) * grant_step) / 100;
         pl->pl_grant_plan = granted + grant_step;
+        limit = (limit * 5) >> 2;
+        if (pl->pl_grant_plan > limit)
+                pl->pl_grant_plan = limit;
 }
 
 /**
@@ -245,36 +248,36 @@ static inline void ldlm_pool_recalc_grant_plan(struct ldlm_pool *pl)
  *
  * \pre ->pl_lock is locked.
  */
-static inline void ldlm_pool_recalc_slv(struct ldlm_pool *pl)
+static void ldlm_pool_recalc_slv(struct ldlm_pool *pl)
 {
-        int grant_usage, granted, grant_plan;
-        __u64 slv, slv_factor;
+        int granted;
+        int grant_plan;
+        int round_up;
+        __u64 slv;
+        __u64 slv_factor;
+        __u64 grant_usage;
         __u32 limit;
 
         slv = pl->pl_server_lock_volume;
         grant_plan = pl->pl_grant_plan;
         limit = ldlm_pool_get_limit(pl);
         granted = cfs_atomic_read(&pl->pl_granted);
+        round_up = granted < limit;
 
-        grant_usage = limit - (granted - grant_plan);
-        if (grant_usage <= 0)
-                grant_usage = 1;
+        grant_usage = max_t(int, limit - (granted - grant_plan), 1);
 
         /*
          * Find out SLV change factor which is the ratio of grant usage
          * from limit. SLV changes as fast as the ratio of grant plan
-         * consumtion. The more locks from grant plan are not consumed
+         * consumption. The more locks from grant plan are not consumed
          * by clients in last interval (idle time), the faster grows
          * SLV. And the opposite, the more grant plan is over-consumed
          * (load time) the faster drops SLV.
          */
-        slv_factor = (grant_usage * 100) / limit;
-        if (2 * abs(granted - limit) > limit) {
-                slv_factor *= slv_factor;
-                slv_factor = dru(slv_factor, 100);
-        }
+        slv_factor = (grant_usage << LDLM_POOL_SLV_SHIFT);
+        do_div(slv_factor, limit);
         slv = slv * slv_factor;
-        slv = dru(slv, 100);
+        slv = dru(slv, LDLM_POOL_SLV_SHIFT, round_up);
 
         if (slv > ldlm_pool_slv_max(limit)) {
                 slv = ldlm_pool_slv_max(limit);
@@ -290,7 +293,7 @@ static inline void ldlm_pool_recalc_slv(struct ldlm_pool *pl)
  *
  * \pre ->pl_lock is locked.
  */
-static inline void ldlm_pool_recalc_stats(struct ldlm_pool *pl)
+static void ldlm_pool_recalc_stats(struct ldlm_pool *pl)
 {
         int grant_plan = pl->pl_grant_plan;
         __u64 slv = pl->pl_server_lock_volume;
@@ -341,37 +344,42 @@ static int ldlm_srv_pool_recalc(struct ldlm_pool *pl)
         time_t recalc_interval_sec;
         ENTRY;
 
-        cfs_spin_lock(&pl->pl_lock);
         recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
-        if (recalc_interval_sec >= pl->pl_recalc_period) {
-                /*
-                 * Recalc SLV after last period. This should be done
-                 * _before_ recalculating new grant plan.
-                 */
-                ldlm_pool_recalc_slv(pl);
+        if (recalc_interval_sec < pl->pl_recalc_period)
+                RETURN(0);
 
-                /*
-                 * Make sure that pool informed obd of last SLV changes.
-                 */
-                ldlm_srv_pool_push_slv(pl);
+        cfs_spin_lock(&pl->pl_lock);
+        recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
+        if (recalc_interval_sec < pl->pl_recalc_period) {
+                cfs_spin_unlock(&pl->pl_lock);
+                RETURN(0);
+        }
+        /*
+         * Recalc SLV after last period. This should be done
+         * _before_ recalculating new grant plan.
+         */
+        ldlm_pool_recalc_slv(pl);
 
-                /*
-                 * Update grant_plan for new period.
-                 */
-                ldlm_pool_recalc_grant_plan(pl);
+        /*
+         * Make sure that pool informed obd of last SLV changes.
+         */
+        ldlm_srv_pool_push_slv(pl);
 
-                pl->pl_recalc_time = cfs_time_current_sec();
-                lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
-                                    recalc_interval_sec);
-        }
+        /*
+         * Update grant_plan for new period.
+         */
+        ldlm_pool_recalc_grant_plan(pl);
 
+        pl->pl_recalc_time = cfs_time_current_sec();
+        lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
+                            recalc_interval_sec);
         cfs_spin_unlock(&pl->pl_lock);
         RETURN(0);
 }
 
 /**
  * This function is used on server side as main entry point for memory
- * preasure handling. It decreases SLV on \a pl according to passed
+ * pressure handling. It decreases SLV on \a pl according to passed
  * \a nr and \a gfp_mask.
  *
  * Our goal here is to decrease SLV such a way that clients hold \a nr
@@ -398,10 +406,10 @@ static int ldlm_srv_pool_shrink(struct ldlm_pool *pl,
         cfs_spin_lock(&pl->pl_lock);
 
         /*
-         * We want shrinker to possibly cause cancelation of @nr locks from
+         * We want shrinker to possibly cause cancellation of @nr locks from
          * clients or grant approximately @nr locks smaller next intervals.
          *
-         * This is why we decresed SLV by @nr. This effect will only be as
+         * This is why we decreased SLV by @nr. This effect will only be as
          * long as one re-calc interval (1s these days) and this should be
          * enough to pass this decreased SLV to all clients. On next recalc
          * interval pool will either increase SLV if locks load is not high
@@ -435,7 +443,6 @@ static int ldlm_srv_pool_shrink(struct ldlm_pool *pl,
 static int ldlm_srv_pool_setup(struct ldlm_pool *pl, int limit)
 {
         struct obd_device *obd;
-        ENTRY;
 
         obd = ldlm_pl2ns(pl)->ns_obd;
         LASSERT(obd != NULL && obd != LP_POISON);
@@ -445,7 +452,7 @@ static int ldlm_srv_pool_setup(struct ldlm_pool *pl, int limit)
         cfs_write_unlock(&obd->obd_pool_lock);
 
         ldlm_pool_set_limit(pl, limit);
-        RETURN(0);
+        return 0;
 }
 
 /**
@@ -456,7 +463,7 @@ static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
         struct obd_device *obd;
 
         /*
-         * Get new SLV and Limit from obd which is updated with comming
+         * Get new SLV and Limit from obd which is updated with coming
          * RPCs.
          */
         obd = ldlm_pl2ns(pl)->ns_obd;
@@ -468,13 +475,17 @@ static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
 }
 
 /**
- * Recalculates client sise pool \a pl according to current SLV and Limit.
+ * Recalculates client size pool \a pl according to current SLV and Limit.
  */
 static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
 {
         time_t recalc_interval_sec;
         ENTRY;
 
+        recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
+        if (recalc_interval_sec < pl->pl_recalc_period)
+                RETURN(0);
+
         cfs_spin_lock(&pl->pl_lock);
         /*
          * Check if we need to recalc lists now.
@@ -512,9 +523,9 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
 }
 
 /**
- * This function is main entry point for memory preasure handling on client side.
- * Main goal of this function is to cancel some number of locks on passed \a pl
- * according to \a nr and \a gfp_mask.
+ * This function is main entry point for memory pressure handling on client
+ * side.  Main goal of this function is to cancel some number of locks on
+ * passed \a pl according to \a nr and \a gfp_mask.
  */
 static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
                                 int nr, unsigned int gfp_mask)
@@ -545,7 +556,7 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
         }
 #ifdef __KERNEL__
         /*
-         * Retrun the number of potentially reclaimable locks.
+         * Return the number of potentially reclaimable locks.
          */
         return ((unused - canceled) / 100) * sysctl_vfs_cache_pressure;
 #else
@@ -573,6 +584,10 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
         time_t recalc_interval_sec;
         int count;
 
+        recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
+        if (recalc_interval_sec <= 0)
+                goto recalc;
+
         cfs_spin_lock(&pl->pl_lock);
         recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
         if (recalc_interval_sec > 0) {
@@ -586,10 +601,10 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
                  */
                 cfs_atomic_set(&pl->pl_grant_rate, 0);
                 cfs_atomic_set(&pl->pl_cancel_rate, 0);
-                cfs_atomic_set(&pl->pl_grant_speed, 0);
         }
         cfs_spin_unlock(&pl->pl_lock);
 
+ recalc:
         if (pl->pl_ops->po_recalc != NULL) {
                 count = pl->pl_ops->po_recalc(pl);
                 lprocfs_counter_add(pl->pl_stats, LDLM_POOL_RECALC_STAT,
@@ -635,10 +650,9 @@ EXPORT_SYMBOL(ldlm_pool_shrink);
  */
 int ldlm_pool_setup(struct ldlm_pool *pl, int limit)
 {
-        ENTRY;
         if (pl->pl_ops->po_setup != NULL)
-                RETURN(pl->pl_ops->po_setup(pl, limit));
-        RETURN(0);
+                return(pl->pl_ops->po_setup(pl, limit));
+        return 0;
 }
 EXPORT_SYMBOL(ldlm_pool_setup);
 
@@ -659,9 +673,9 @@ static int lprocfs_rd_pool_state(char *page, char **start, off_t off,
         grant_plan = pl->pl_grant_plan;
         granted = cfs_atomic_read(&pl->pl_granted);
         grant_rate = cfs_atomic_read(&pl->pl_grant_rate);
-        lvf = cfs_atomic_read(&pl->pl_lock_volume_factor);
-        grant_speed = cfs_atomic_read(&pl->pl_grant_speed);
         cancel_rate = cfs_atomic_read(&pl->pl_cancel_rate);
+        grant_speed = grant_rate - cancel_rate;
+        lvf = cfs_atomic_read(&pl->pl_lock_volume_factor);
         grant_step = ldlm_pool_t2gsp(pl->pl_recalc_period);
         cfs_spin_unlock(&pl->pl_lock);
 
@@ -690,6 +704,20 @@ static int lprocfs_rd_pool_state(char *page, char **start, off_t off,
         return nr;
 }
 
+static int lprocfs_rd_grant_speed(char *page, char **start, off_t off,
+                                  int count, int *eof, void *data)
+{
+        struct ldlm_pool *pl = data;
+        int               grant_speed;
+
+        cfs_spin_lock(&pl->pl_lock);
+        /* serialize with ldlm_pool_recalc */
+        grant_speed = cfs_atomic_read(&pl->pl_grant_rate) -
+                      cfs_atomic_read(&pl->pl_cancel_rate);
+        cfs_spin_unlock(&pl->pl_lock);
+        return lprocfs_rd_uint(page, start, off, count, eof, &grant_speed);
+}
+
 LDLM_POOL_PROC_READER(grant_plan, int);
 LDLM_POOL_PROC_READER(recalc_period, int);
 LDLM_POOL_PROC_WRITER(recalc_period, int);
@@ -742,8 +770,8 @@ static int ldlm_pool_proc_init(struct ldlm_pool *pl)
         lprocfs_add_vars(pl->pl_proc_dir, pool_vars, 0);
 
         snprintf(var_name, MAX_STRING_SIZE, "grant_speed");
-        pool_vars[0].data = &pl->pl_grant_speed;
-        pool_vars[0].read_fptr = lprocfs_rd_atomic;
+        pool_vars[0].data = pl;
+        pool_vars[0].read_fptr = lprocfs_rd_grant_speed;
         lprocfs_add_vars(pl->pl_proc_dir, pool_vars, 0);
 
         snprintf(var_name, MAX_STRING_SIZE, "cancel_rate");
@@ -853,7 +881,6 @@ int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
 
         cfs_atomic_set(&pl->pl_grant_rate, 0);
         cfs_atomic_set(&pl->pl_cancel_rate, 0);
-        cfs_atomic_set(&pl->pl_grant_speed, 0);
         pl->pl_grant_plan = LDLM_POOL_GP(LDLM_POOL_HOST_L);
 
         snprintf(pl->pl_name, sizeof(pl->pl_name), "ldlm-pool-%s-%d",
@@ -866,7 +893,7 @@ int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
                 pl->pl_server_lock_volume = ldlm_pool_slv_max(LDLM_POOL_HOST_L);
         } else {
                 ldlm_pool_set_limit(pl, 1);
-                pl->pl_server_lock_volume = 1;
+                pl->pl_server_lock_volume = 0;
                 pl->pl_ops = &ldlm_cli_pool_ops;
                 pl->pl_recalc_period = LDLM_POOL_CLI_DEF_RECALC_PERIOD;
         }
@@ -909,13 +936,9 @@ void ldlm_pool_add(struct ldlm_pool *pl, struct ldlm_lock *lock)
          */
         if (lock->l_resource->lr_type == LDLM_FLOCK)
                 return;
-        ENTRY;
 
-        LDLM_DEBUG(lock, "add lock to pool");
         cfs_atomic_inc(&pl->pl_granted);
         cfs_atomic_inc(&pl->pl_grant_rate);
-        cfs_atomic_inc(&pl->pl_grant_speed);
-
         lprocfs_counter_incr(pl->pl_stats, LDLM_POOL_GRANT_STAT);
         /*
          * Do not do pool recalc for client side as all locks which
@@ -925,7 +948,6 @@ void ldlm_pool_add(struct ldlm_pool *pl, struct ldlm_lock *lock)
          */
         if (ns_is_server(ldlm_pl2ns(pl)))
                 ldlm_pool_recalc(pl);
-        EXIT;
 }
 EXPORT_SYMBOL(ldlm_pool_add);
 
@@ -939,19 +961,15 @@ void ldlm_pool_del(struct ldlm_pool *pl, struct ldlm_lock *lock)
          */
         if (lock->l_resource->lr_type == LDLM_FLOCK)
                 return;
-        ENTRY;
 
-        LDLM_DEBUG(lock, "del lock from pool");
         LASSERT(cfs_atomic_read(&pl->pl_granted) > 0);
         cfs_atomic_dec(&pl->pl_granted);
         cfs_atomic_inc(&pl->pl_cancel_rate);
-        cfs_atomic_dec(&pl->pl_grant_speed);
 
         lprocfs_counter_incr(pl->pl_stats, LDLM_POOL_CANCEL_STAT);
 
         if (ns_is_server(ldlm_pl2ns(pl)))
                 ldlm_pool_recalc(pl);
-        EXIT;
 }
 EXPORT_SYMBOL(ldlm_pool_del);
 
@@ -1061,7 +1079,8 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
         struct ldlm_namespace *ns;
         void *cookie;
 
-        if (nr != 0 && !(gfp_mask & __GFP_FS))
+        if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
+            !(gfp_mask & __GFP_FS))
                 return -1;
 
         CDEBUG(D_DLMTRACE, "Request to shrink %d %s locks from all pools\n",
@@ -1167,9 +1186,9 @@ void ldlm_pools_recalc(ldlm_side_t client)
 
                         /*
                          * Set the modest pools limit equal to their avg granted
-                         * locks + 5%.
+                         * locks + ~6%.
                          */
-                        l += dru(l * LDLM_POOLS_MODEST_MARGIN, 100);
+                        l += dru(l, LDLM_POOLS_MODEST_MARGIN_SHIFT, 0);
                         ldlm_pool_setup(&ns->ns_pool, l);
                         nr_l += l;
                         nr_p++;