diff options
author | Jack Steiner <steiner@sgi.com> | 2009-06-17 16:28:30 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 13:04:03 -0700 |
commit | 7e796a72a2691d7094fd62da61097294d0d59ce4 (patch) | |
tree | 9e8d4e1eae9a2d23f604f0af5d101979dc7afec7 /drivers/misc/sgi-gru | |
parent | d6e2fbce0d70c2072a1c478dbd37b34d27129d74 (diff) | |
download | linux-stable-7e796a72a2691d7094fd62da61097294d0d59ce4.tar.gz linux-stable-7e796a72a2691d7094fd62da61097294d0d59ce4.tar.bz2 linux-stable-7e796a72a2691d7094fd62da61097294d0d59ce4.zip |
gru: collect per-context user statistics
Collect GRU statistics for each user GRU context. Statistics are kept for
TLB misses & content resource contention. Add user request for retrieving
the statistics.
Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc/sgi-gru')
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 27 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grufile.c | 3 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grulib.h | 18 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grumain.c | 1 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grutables.h | 3 |
5 files changed, 52 insertions, 0 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 6d0681236db5..cdd151b30dc7 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -498,6 +498,7 @@ irqreturn_t gru_intr(int irq, void *dev_id) */ if (!gts->ts_force_cch_reload && down_read_trylock(>s->ts_mm->mmap_sem)) { + gts->ustats.fmm_tlbdropin++; gru_try_dropin(gts, tfh, NULL); up_read(>s->ts_mm->mmap_sem); } else { @@ -516,6 +517,7 @@ static int gru_user_dropin(struct gru_thread_state *gts, struct gru_mm_struct *gms = gts->ts_gms; int ret; + gts->ustats.upm_tlbdropin++; while (1) { wait_event(gms->ms_wait_queue, atomic_read(&gms->ms_range_active) == 0); @@ -719,6 +721,31 @@ int gru_user_flush_tlb(unsigned long arg) } /* + * Fetch GSEG statisticss + */ +long gru_get_gseg_statistics(unsigned long arg) +{ + struct gru_thread_state *gts; + struct gru_get_gseg_statistics_req req; + + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + gts = gru_find_lock_gts(req.gseg); + if (gts) { + memcpy(&req.stats, >s->ustats, sizeof(gts->ustats)); + gru_unlock_gts(gts); + } else { + memset(&req.stats, 0, sizeof(gts->ustats)); + } + + if (copy_to_user((void __user *)arg, &req, sizeof(req))) + return -EFAULT; + + return 0; +} + +/* * Register the current task as the user of the GSEG slice. * Needed for TLB fault interrupt targeting. */ diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index e22012db239e..0d1c8b8c1c12 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -251,6 +251,9 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, case GRU_USER_CALL_OS: err = gru_handle_user_call_os(arg); break; + case GRU_GET_GSEG_STATISTICS: + err = gru_get_gseg_statistics(arg); + break; case GRU_KTEST: err = gru_ktest(arg); break; diff --git a/drivers/misc/sgi-gru/grulib.h b/drivers/misc/sgi-gru/grulib.h index 87586551d16f..c5865dd19eec 100644 --- a/drivers/misc/sgi-gru/grulib.h +++ b/drivers/misc/sgi-gru/grulib.h @@ -50,6 +50,9 @@ /* For dumpping GRU chiplet state */ #define GRU_DUMP_CHIPLET_STATE _IOWR(GRU_IOCTL_NUM, 11, void *) +/* For getting gseg statistics */ +#define GRU_GET_GSEG_STATISTICS _IOWR(GRU_IOCTL_NUM, 12, void *) + /* For user TLB flushing (primarily for tests) */ #define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *) @@ -61,6 +64,21 @@ #define CONTEXT_WINDOW_BYTES(th) (GRU_GSEG_PAGESIZE * (th)) #define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) +#define GSEG_START(cb) ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1))) + +/* + * Statictics kept on a per-GTS basis. + */ +struct gts_statistics { + unsigned long fmm_tlbdropin; + unsigned long upm_tlbdropin; + unsigned long context_stolen; +}; + +struct gru_get_gseg_statistics_req { + unsigned long gseg; + struct gts_statistics stats; +}; /* * Structure used to pass TLB flush parameters to the driver diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index e38a0f1775ff..347004e4f591 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -744,6 +744,7 @@ void gru_steal_context(struct gru_thread_state *gts, int blade_id) spin_unlock(&blade->bs_lock); if (ngts) { + gts->ustats.context_stolen++; ngts->ts_steal_jiffies = jiffies; gru_unload_context(ngts, is_kernel_context(ngts) ? 0 : 1); gts_stolen(ngts, blade); diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 9761bfee8669..63b76e2732ff 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -148,6 +148,7 @@ #include <linux/wait.h> #include <linux/mmu_notifier.h> #include "gru.h" +#include "grulib.h" #include "gruhandles.h" extern struct gru_stats_s gru_stats; @@ -388,6 +389,7 @@ struct gru_thread_state { allocated CB */ int ts_data_valid; /* Indicates if ts_gdata has valid data */ + struct gts_statistics ustats; /* User statistics */ unsigned long ts_gdata[0]; /* save area for GRU data (CB, DS, CBE) */ }; @@ -641,6 +643,7 @@ extern void gru_tgh_flush_init(struct gru_state *gru); extern int gru_kservices_init(void); extern void gru_kservices_exit(void); extern int gru_dump_chiplet_request(unsigned long arg); +extern long gru_get_gseg_statistics(unsigned long arg); extern irqreturn_t gru_intr(int irq, void *dev_id); extern int gru_handle_user_call_os(unsigned long address); extern int gru_user_flush_tlb(unsigned long arg); |