Skip to content

Commit 3bcd066

Browse files
xzpeterbonzini
authored andcommitted
KVM: X86: Introduce mmu_rmaps_stat per-vm debugfs file
Use this file to dump rmap statistic information. The statistic is done by calculating the rmap count and the result is log-2-based. An example output of this looks like (idle 6GB guest, right after boot linux): Rmap_Count: 0 1 2-3 4-7 8-15 16-31 32-63 64-127 128-255 256-511 512-1023 Level=4K: 3086676 53045 12330 1272 502 121 76 2 0 0 0 Level=2M: 5947 231 0 0 0 0 0 0 0 0 0 Level=1G: 32 0 0 0 0 0 0 0 0 0 0 Signed-off-by: Peter Xu <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 4139b19 commit 3bcd066

File tree

3 files changed

+132
-0
lines changed

3 files changed

+132
-0
lines changed

arch/x86/kvm/debugfs.c

+111
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <linux/kvm_host.h>
88
#include <linux/debugfs.h>
99
#include "lapic.h"
10+
#include "mmu.h"
11+
#include "mmu/mmu_internal.h"
1012

1113
static int vcpu_get_timer_advance_ns(void *data, u64 *val)
1214
{
@@ -73,3 +75,112 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_
7375
&vcpu_tsc_scaling_frac_fops);
7476
}
7577
}
78+
79+
/*
80+
* This covers statistics <1024 (11=log(1024)+1), which should be enough to
81+
* cover RMAP_RECYCLE_THRESHOLD.
82+
*/
83+
#define RMAP_LOG_SIZE 11
84+
85+
static const char *kvm_lpage_str[KVM_NR_PAGE_SIZES] = { "4K", "2M", "1G" };
86+
87+
static int kvm_mmu_rmaps_stat_show(struct seq_file *m, void *v)
88+
{
89+
struct kvm_rmap_head *rmap;
90+
struct kvm *kvm = m->private;
91+
struct kvm_memory_slot *slot;
92+
struct kvm_memslots *slots;
93+
unsigned int lpage_size, index;
94+
/* Still small enough to be on the stack */
95+
unsigned int *log[KVM_NR_PAGE_SIZES], *cur;
96+
int i, j, k, l, ret;
97+
98+
ret = -ENOMEM;
99+
memset(log, 0, sizeof(log));
100+
for (i = 0; i < KVM_NR_PAGE_SIZES; i++) {
101+
log[i] = kcalloc(RMAP_LOG_SIZE, sizeof(unsigned int), GFP_KERNEL);
102+
if (!log[i])
103+
goto out;
104+
}
105+
106+
mutex_lock(&kvm->slots_lock);
107+
write_lock(&kvm->mmu_lock);
108+
109+
for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
110+
slots = __kvm_memslots(kvm, i);
111+
for (j = 0; j < slots->used_slots; j++) {
112+
slot = &slots->memslots[j];
113+
for (k = 0; k < KVM_NR_PAGE_SIZES; k++) {
114+
rmap = slot->arch.rmap[k];
115+
lpage_size = kvm_mmu_slot_lpages(slot, k + 1);
116+
cur = log[k];
117+
for (l = 0; l < lpage_size; l++) {
118+
index = ffs(pte_list_count(&rmap[l]));
119+
if (WARN_ON_ONCE(index >= RMAP_LOG_SIZE))
120+
index = RMAP_LOG_SIZE - 1;
121+
cur[index]++;
122+
}
123+
}
124+
}
125+
}
126+
127+
write_unlock(&kvm->mmu_lock);
128+
mutex_unlock(&kvm->slots_lock);
129+
130+
/* index=0 counts no rmap; index=1 counts 1 rmap */
131+
seq_printf(m, "Rmap_Count:\t0\t1\t");
132+
for (i = 2; i < RMAP_LOG_SIZE; i++) {
133+
j = 1 << (i - 1);
134+
k = (1 << i) - 1;
135+
seq_printf(m, "%d-%d\t", j, k);
136+
}
137+
seq_printf(m, "\n");
138+
139+
for (i = 0; i < KVM_NR_PAGE_SIZES; i++) {
140+
seq_printf(m, "Level=%s:\t", kvm_lpage_str[i]);
141+
cur = log[i];
142+
for (j = 0; j < RMAP_LOG_SIZE; j++)
143+
seq_printf(m, "%d\t", cur[j]);
144+
seq_printf(m, "\n");
145+
}
146+
147+
ret = 0;
148+
out:
149+
for (i = 0; i < KVM_NR_PAGE_SIZES; i++)
150+
kfree(log[i]);
151+
152+
return ret;
153+
}
154+
155+
static int kvm_mmu_rmaps_stat_open(struct inode *inode, struct file *file)
156+
{
157+
struct kvm *kvm = inode->i_private;
158+
159+
if (!kvm_get_kvm_safe(kvm))
160+
return -ENOENT;
161+
162+
return single_open(file, kvm_mmu_rmaps_stat_show, kvm);
163+
}
164+
165+
static int kvm_mmu_rmaps_stat_release(struct inode *inode, struct file *file)
166+
{
167+
struct kvm *kvm = inode->i_private;
168+
169+
kvm_put_kvm(kvm);
170+
171+
return single_release(inode, file);
172+
}
173+
174+
static const struct file_operations mmu_rmaps_stat_fops = {
175+
.open = kvm_mmu_rmaps_stat_open,
176+
.read = seq_read,
177+
.llseek = seq_lseek,
178+
.release = kvm_mmu_rmaps_stat_release,
179+
};
180+
181+
int kvm_arch_create_vm_debugfs(struct kvm *kvm)
182+
{
183+
debugfs_create_file("mmu_rmaps_stat", 0644, kvm->debugfs_dentry, kvm,
184+
&mmu_rmaps_stat_fops);
185+
return 0;
186+
}

arch/x86/kvm/mmu/mmu.c

+20
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,26 @@ static bool pte_list_destroy(struct kvm_rmap_head *rmap_head)
10351035
return true;
10361036
}
10371037

1038+
unsigned int pte_list_count(struct kvm_rmap_head *rmap_head)
1039+
{
1040+
struct pte_list_desc *desc;
1041+
unsigned int count = 0;
1042+
1043+
if (!rmap_head->val)
1044+
return 0;
1045+
else if (!(rmap_head->val & 1))
1046+
return 1;
1047+
1048+
desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
1049+
1050+
while (desc) {
1051+
count += desc->spte_count;
1052+
desc = desc->more;
1053+
}
1054+
1055+
return count;
1056+
}
1057+
10381058
static struct kvm_rmap_head *gfn_to_rmap(gfn_t gfn, int level,
10391059
const struct kvm_memory_slot *slot)
10401060
{

arch/x86/kvm/mmu/mmu_internal.h

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
131131
int min_level);
132132
void kvm_flush_remote_tlbs_with_address(struct kvm *kvm,
133133
u64 start_gfn, u64 pages);
134+
unsigned int pte_list_count(struct kvm_rmap_head *rmap_head);
134135

135136
/*
136137
* Return values of handle_mmio_page_fault, mmu.page_fault, and fast_page_fault().

0 commit comments

Comments
 (0)