Skip to content

Commit

Permalink
x86, generic: CPA add statistics about state of direct mapping v4
Browse files Browse the repository at this point in the history
Add information about the mapping state of the direct mapping to
/proc/meminfo. I chose /proc/meminfo because that is where all the other
memory statistics are too and it is a generally useful metric even
outside debugging situations. A lot of split kernel pages means the
kernel will run slower.

This way we can see how many large pages are really used for it and how
many are split.

Useful for general insight into the kernel.

v2: Add hotplug locking to 64bit to plug a very obscure theoretical race.
    32bit doesn't need it because it doesn't support hotadd for lowmem.
    Fix some typos
v3: Rename dpages_cnt
    Add CONFIG ifdef for count update as requested by tglx
    Expand description
v4: Fix stupid bugs added in v3
    Move update_page_count to pageattr.c

Signed-off-by: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Andi Kleen authored and Ingo Molnar committed Jul 8, 2008
1 parent 1b40a89 commit ce0c0e5
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 0 deletions.
5 changes: 5 additions & 0 deletions arch/x86/mm/init_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
unsigned pages_2m = 0, pages_4k = 0;

pgd_idx = pgd_index(PAGE_OFFSET);
pgd = pgd_base + pgd_idx;
Expand Down Expand Up @@ -197,6 +198,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
is_kernel_text(addr2))
prot = PAGE_KERNEL_LARGE_EXEC;

pages_2m++;
set_pmd(pmd, pfn_pmd(pfn, prot));

pfn += PTRS_PER_PTE;
Expand All @@ -213,11 +215,14 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
if (is_kernel_text(addr))
prot = PAGE_KERNEL_EXEC;

pages_4k++;
set_pte(pte, pfn_pte(pfn, prot));
}
max_pfn_mapped = pfn;
}
}
update_page_count(PG_LEVEL_2M, pages_2m);
update_page_count(PG_LEVEL_4K, pages_4k);
}

static inline int page_kills_ppro(unsigned long pagenr)
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/mm/init_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ __meminit void early_iounmap(void *addr, unsigned long size)
static unsigned long __meminit
phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
{
unsigned long pages = 0;

int i = pmd_index(address);

for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
Expand All @@ -328,9 +330,11 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
if (pmd_val(*pmd))
continue;

pages++;
set_pte((pte_t *)pmd,
pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
}
update_page_count(PG_LEVEL_2M, pages);
return address;
}

Expand All @@ -350,6 +354,7 @@ phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end)
static unsigned long __meminit
phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
{
unsigned long pages = 0;
unsigned long last_map_addr = end;
int i = pud_index(addr);

Expand All @@ -374,6 +379,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
}

if (direct_gbpages) {
pages++;
set_pte((pte_t *)pud,
pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
Expand All @@ -390,6 +396,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
unmap_low_page(pmd);
}
__flush_tlb_all();
update_page_count(PG_LEVEL_1G, pages);

return last_map_addr >> PAGE_SHIFT;
}
Expand Down
35 changes: 35 additions & 0 deletions arch/x86/mm/pageattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ struct cpa_data {
unsigned force_split : 1;
};

static unsigned long direct_pages_count[PG_LEVEL_NUM];

void __meminit update_page_count(int level, unsigned long pages)
{
#ifdef CONFIG_PROC_FS
unsigned long flags;
/* Protect against CPA */
spin_lock_irqsave(&pgd_lock, flags);
direct_pages_count[level] += pages;
spin_unlock_irqrestore(&pgd_lock, flags);
#endif
}

#ifdef CONFIG_X86_64

static inline unsigned long highmap_start_pfn(void)
Expand Down Expand Up @@ -500,6 +513,12 @@ static int split_large_page(pte_t *kpte, unsigned long address)
for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, ref_prot));

if (address >= (unsigned long)__va(0) &&
address < (unsigned long)__va(max_pfn_mapped << PAGE_SHIFT)) {
direct_pages_count[level]--;
direct_pages_count[level - 1] += PTRS_PER_PTE;
}

/*
* Install the new, split up pagetable. Important details here:
*
Expand Down Expand Up @@ -1029,6 +1048,22 @@ bool kernel_page_present(struct page *page)

#endif /* CONFIG_DEBUG_PAGEALLOC */

#ifdef CONFIG_PROC_FS
int arch_report_meminfo(char *page)
{
int n;
n = sprintf(page, "DirectMap4k: %8lu\n"
"DirectMap2M: %8lu\n",
direct_pages_count[PG_LEVEL_4K],
direct_pages_count[PG_LEVEL_2M]);
#ifdef CONFIG_X86_64
n += sprintf(page + n, "DirectMap1G: %8lu\n",
direct_pages_count[PG_LEVEL_1G]);
#endif
return n;
}
#endif

/*
* The testcases use internal knowledge of the implementation that shouldn't
* be exposed to the rest of the kernel. Include these directly here.
Expand Down
7 changes: 7 additions & 0 deletions fs/proc/proc_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ static int uptime_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}

int __attribute__((weak)) arch_report_meminfo(char *page)
{
return 0;
}

static int meminfo_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
Expand Down Expand Up @@ -221,6 +226,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off,

len += hugetlb_report_meminfo(page + len);

len += arch_report_meminfo(page + len);

return proc_calc_metrics(page, start, off, count, eof, len);
#undef K
}
Expand Down
3 changes: 3 additions & 0 deletions include/asm-x86/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,11 @@ enum {
PG_LEVEL_4K,
PG_LEVEL_2M,
PG_LEVEL_1G,
PG_LEVEL_NUM
};

void update_page_count(int level, unsigned long pages);

/*
* Helper function that returns the kernel pagetable entry controlling
* the virtual address 'address'. NULL means no pagetable entry present.
Expand Down

0 comments on commit ce0c0e5

Please sign in to comment.