struct lprocfs_counter lp_cntr[0];
};
+#define LPROCFS_GET_NUM_CPU 0x0001
+#define LPROCFS_GET_SMP_ID 0x0002
+
+enum lprocfs_stats_flags {
+ LPROCFS_STATS_FLAG_NOPERCPU = 0x0001, /* stats have no percpu
+ * area and need locking */
+};
struct lprocfs_stats {
unsigned int ls_num; /* # of counters */
unsigned int ls_percpu_size;
+ int ls_flags; /* See LPROCFS_STATS_FLAG_* */
+ spinlock_t ls_lock; /* Lock used only when there are
+ * no percpu stats areas */
struct lprocfs_percpu *ls_percpu[0];
};
#ifdef LPROCFS
+static inline int lprocfs_stats_lock(struct lprocfs_stats *stats, int type)
+{
+ int rc = 0;
+
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+ if (type & LPROCFS_GET_NUM_CPU)
+ rc = 1;
+ if (type & LPROCFS_GET_SMP_ID)
+ rc = 0;
+ spin_lock(&stats->ls_lock);
+ } else {
+ if (type & LPROCFS_GET_NUM_CPU)
+ rc = num_possible_cpus();
+ if (type & LPROCFS_GET_SMP_ID)
+ rc = smp_processor_id();
+ }
+ return rc;
+}
+
+static inline void lprocfs_stats_unlock(struct lprocfs_stats *stats)
+{
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
+ spin_unlock(&stats->ls_lock);
+}
+
/* Two optimized LPROCFS counter increment functions are provided:
* lprocfs_counter_incr(cntr, value) - optimized for by-one counters
* lprocfs_counter_add(cntr) - use for multi-valued counters
long amount)
{
struct lprocfs_counter *percpu_cntr;
+ int smp_id;
if (stats == NULL)
return;
- percpu_cntr = &(stats->ls_percpu[smp_processor_id()]->lp_cntr[idx]);
+
+ /* With per-client stats, statistics are allocated only for
+ * single CPU area, so the smp_id should be 0 always. */
+ smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID);
+
+ percpu_cntr = &(stats->ls_percpu[smp_id]->lp_cntr[idx]);
atomic_inc(&percpu_cntr->lc_cntl.la_entry);
percpu_cntr->lc_count++;
percpu_cntr->lc_max = amount;
}
atomic_inc(&percpu_cntr->lc_cntl.la_exit);
+ lprocfs_stats_unlock(stats);
}
static inline void lprocfs_counter_incr(struct lprocfs_stats *stats, int idx)
{
struct lprocfs_counter *percpu_cntr;
+ int smp_id;
if (stats == NULL)
return;
- percpu_cntr = &(stats->ls_percpu[smp_processor_id()]->lp_cntr[idx]);
+
+ smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID);
+ percpu_cntr = &(stats->ls_percpu[smp_id]->lp_cntr[idx]);
+
atomic_inc(&percpu_cntr->lc_cntl.la_entry);
percpu_cntr->lc_count++;
atomic_inc(&percpu_cntr->lc_cntl.la_exit);
+ lprocfs_stats_unlock(stats);
}
-extern struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num);
+extern struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
+ enum lprocfs_stats_flags flags);
extern void lprocfs_clear_stats(struct lprocfs_stats *stats);
extern void lprocfs_free_stats(struct lprocfs_stats **stats);
extern void lprocfs_init_ops_stats(int num_private_stats,
const char *name, const char *units)
{ return; }
-static inline struct lprocfs_stats* lprocfs_alloc_stats(unsigned int num)
+static inline struct lprocfs_stats* lprocfs_alloc_stats(unsigned int num,
+ int client_stat)
{ return NULL; }
static inline void lprocfs_clear_stats(struct lprocfs_stats *stats)
{ return; }
lprocfs_add_vars(pl->pl_proc_dir, pool_vars, 0);
pl->pl_stats = lprocfs_alloc_stats(LDLM_POOL_LAST_STAT -
- LDLM_POOL_GRANTED_STAT);
+ LDLM_POOL_GRANTED_STAT, 0);
if (!pl->pl_stats)
GOTO(out_free_name, rc = -ENOMEM);
entry->data = sbi;
/* File operations stats */
- sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES);
+ sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES, 0);
if (sbi->ll_stats == NULL)
GOTO(out, err = -ENOMEM);
/* do counter init */
return rc;
num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
LPROC_MDS_LAST - 1;
- exp->exp_ops_stats = lprocfs_alloc_stats(num_stats);
+ exp->exp_ops_stats = lprocfs_alloc_stats(num_stats,
+ LPROCFS_STATS_FLAG_NOPERCPU);
if (exp->exp_ops_stats == NULL)
return -ENOMEM;
lprocfs_init_ops_stats(LPROC_MDS_LAST, exp->exp_ops_stats);
return 0;
}
-struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
+struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
+ enum lprocfs_stats_flags flags)
{
struct lprocfs_stats *stats;
struct lprocfs_percpu *percpu;
unsigned int percpusize;
unsigned int i;
+ unsigned int num_cpu;
if (num == 0)
return NULL;
- OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
+ if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
+ num_cpu = 1;
+ else
+ num_cpu = num_possible_cpus();
+
+ OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
if (stats == NULL)
return NULL;
- percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
- stats->ls_percpu_size = num_online_cpus() * percpusize;
+ if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+ stats->ls_flags = flags;
+ spin_lock_init(&stats->ls_lock);
+ /* Use this lock only if there are no percpu areas */
+ } else {
+ stats->ls_flags = 0;
+ }
+
+ percpusize = offsetof(typeof(*percpu), lp_cntr[num]);
+ if (num_cpu > 1)
+ percpusize = L1_CACHE_ALIGN(percpusize);
+
+ stats->ls_percpu_size = num_cpu * percpusize;
OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
if (stats->ls_percpu[0] == NULL) {
OBD_FREE(stats, offsetof(typeof(*stats),
- ls_percpu[num_online_cpus()]));
+ ls_percpu[num_cpu]));
return NULL;
}
stats->ls_num = num;
- for (i = 1; i < num_online_cpus(); i++)
+ for (i = 1; i < num_cpu; i++)
stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
percpusize;
void lprocfs_free_stats(struct lprocfs_stats **statsh)
{
struct lprocfs_stats *stats = *statsh;
+ unsigned int num_cpu;
if (stats == NULL || stats->ls_num == 0)
return;
*statsh = NULL;
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
+ num_cpu = 1;
+ else
+ num_cpu = num_possible_cpus();
+
OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
- OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
+ OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
}
void lprocfs_clear_stats(struct lprocfs_stats *stats)
{
struct lprocfs_counter *percpu_cntr;
int i,j;
+ unsigned int num_cpu;
- for (i = 0; i < num_online_cpus(); i++) {
+ num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
+
+ for (i = 0; i < num_cpu; i++) {
for (j = 0; j < stats->ls_num; j++) {
percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
atomic_inc(&percpu_cntr->lc_cntl.la_entry);
atomic_inc(&percpu_cntr->lc_cntl.la_exit);
}
}
+
+ lprocfs_stats_unlock(stats);
}
static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
struct lprocfs_counter *cntr = v;
struct lprocfs_counter t, ret = { .lc_min = ~(__u64)0 };
int i, idx, rc;
+ unsigned int num_cpu;
if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
struct timeval now;
}
idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
- for (i = 0; i < num_online_cpus(); i++) {
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
+ num_cpu = 1;
+ else
+ num_cpu = num_possible_cpus();
+
+ for (i = 0; i < num_cpu; i++) {
struct lprocfs_counter *percpu_cntr =
&(stats->ls_percpu[i])->lp_cntr[idx];
int centry;
{
struct lprocfs_counter *c;
int i;
+ unsigned int num_cpu;
LASSERT(stats != NULL);
- for (i = 0; i < num_online_cpus(); i++) {
+
+ num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
+
+ for (i = 0; i < num_cpu; i++) {
c = &(stats->ls_percpu[i]->lp_cntr[index]);
c->lc_config = conf;
c->lc_count = 0;
c->lc_name = name;
c->lc_units = units;
}
+
+ lprocfs_stats_unlock(stats);
}
EXPORT_SYMBOL(lprocfs_counter_init);
num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
num_private_stats - 1 /* o_owner */;
- stats = lprocfs_alloc_stats(num_stats);
+ stats = lprocfs_alloc_stats(num_stats, 0);
if (stats == NULL)
return -ENOMEM;
num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
num_private_stats;
- stats = lprocfs_alloc_stats(num_stats);
+ stats = lprocfs_alloc_stats(num_stats, 0);
if (stats == NULL)
return -ENOMEM;
GOTO(out, rc);
/* Always add ldlm stats */
exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC
- - LDLM_FIRST_OPC);
+ - LDLM_FIRST_OPC, 0);
if (exp->exp_ldlm_stats == NULL) {
lprocfs_remove(&exp->exp_proc);
GOTO(out, rc = -ENOMEM);
if (nr == 0)
RETURN(0);
- *stats = lprocfs_alloc_stats(nr);
+ *stats = lprocfs_alloc_stats(nr, 0);
if (*stats != NULL) {
result = lprocfs_register_stats(entry, name, *stats);
if (result == 0) {
/* Create a per export proc entry for ops stats */
num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
LPROC_FILTER_LAST - 1;
- exp->exp_ops_stats = lprocfs_alloc_stats(num_stats);
+ exp->exp_ops_stats = lprocfs_alloc_stats(num_stats,
+ LPROCFS_STATS_FLAG_NOPERCPU);
if (exp->exp_ops_stats == NULL)
RETURN(-ENOMEM);
lprocfs_init_ops_stats(LPROC_FILTER_LAST, exp->exp_ops_stats);
LASSERT(*procroot_ret == NULL);
LASSERT(*stats_ret == NULL);
- svc_stats = lprocfs_alloc_stats(PTLRPC_LAST_CNTR + LUSTRE_MAX_OPCODES);
+ svc_stats = lprocfs_alloc_stats(PTLRPC_LAST_CNTR + LUSTRE_MAX_OPCODES, 0);
if (svc_stats == NULL)
return;