Hi Dave,
On 2/27/2018 4:45 PM, Kazuhito Hagio wrote:
[...]
> First, the mem_section numbers are ascending. They may not
necessarily start
> with 0, and there may be holes, but they are ascending. That being the case,
> there is no need for is_page_ptr() to walk through NR_MEM_SECTIONS() worth
> of entries, because there will be an ending number that's typically much
> smaller. Even on a 256GB dumpfile I have on hand, which has a NR_MEM_SECTIONS()
> value of 524288, the largest valid section number is 2055. (What is the smallest
> and largest number that you see on whatever large-memory system that you are
> testing with?)
>
> In any case, let's store the largest section number during initialization in
> the vm_table, and use it as a delimeter in is_page_ptr().
I agree with you. This will improve the worst case of the loop. Also,
if the binary search is implemented in the future, it could be utilized.
(The largest valid section numbers of each architecture in my test logs
are 1543 on a 192GB x86_64 and 2047 on a 32GB ppc64.)
I checked and tested the former patch you proposed below as it is
and I didn't find any problem. Could you merge this?
(or is there anything I should do?)
> diff --git a/defs.h b/defs.h
> index aa17792..8768fd5 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2369,6 +2369,7 @@ struct vm_table { /* kernel VM-related data */
> ulong mask;
> char *name;
> } *pageflags_data;
> + ulong max_mem_section_nr;
> };
>
> #define NODES (0x1)
> diff --git a/memory.c b/memory.c
> index 0df8ecc..6770937 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -255,7 +255,7 @@ static void PG_reserved_flag_init(void);
> static void PG_slab_flag_init(void);
> static ulong nr_blockdev_pages(void);
> void sparse_mem_init(void);
> -void dump_mem_sections(void);
> +void dump_mem_sections(int);
> void list_mem_sections(void);
> ulong sparse_decode_mem_map(ulong, ulong);
> char *read_mem_section(ulong);
> @@ -13350,7 +13350,7 @@ is_page_ptr(ulong addr, physaddr_t *phys)
> physaddr_t section_paddr;
>
> if (IS_SPARSEMEM()) {
> - nr_mem_sections = NR_MEM_SECTIONS();
> + nr_mem_sections = vt->max_mem_section_nr+1;
> for (nr = 0; nr < nr_mem_sections ; nr++) {
> if ((sec_addr = valid_section_nr(nr))) {
> coded_mem_map = section_mem_map_addr(sec_addr);
> @@ -13668,6 +13668,7 @@ dump_vm_table(int verbose)
> fprintf(fp, " swap_info_struct: %lx\n",
(ulong)vt->swap_info_struct);
> fprintf(fp, " mem_sec: %lx\n", (ulong)vt->mem_sec);
> fprintf(fp, " mem_section: %lx\n", (ulong)vt->mem_section);
> + fprintf(fp, " max_mem_section_nr: %ld\n", vt->max_mem_section_nr);
> fprintf(fp, " ZONE_HIGHMEM: %d\n", vt->ZONE_HIGHMEM);
> fprintf(fp, "node_online_map_len: %d\n", vt->node_online_map_len);
> if (vt->node_online_map_len) {
> @@ -16295,8 +16296,8 @@ dump_memory_nodes(int initialize)
> vt->numnodes = n;
> }
>
> - if (!initialize && IS_SPARSEMEM())
> - dump_mem_sections();
> + if (IS_SPARSEMEM())
> + dump_mem_sections(initialize);
> }
>
> /*
> @@ -17128,9 +17129,9 @@ pfn_to_map(ulong pfn)
> }
>
> void
> -dump_mem_sections(void)
> +dump_mem_sections(int initialize)
> {
> - ulong nr,addr;
> + ulong nr, max, addr;
> ulong nr_mem_sections;
> ulong coded_mem_map, mem_map, pfn;
> char buf1[BUFSIZE];
> @@ -17140,6 +17141,15 @@ dump_mem_sections(void)
>
> nr_mem_sections = NR_MEM_SECTIONS();
>
> + if (initialize) {
> + for (nr = max = 0; nr < nr_mem_sections ; nr++) {
> + if (valid_section_nr(nr))
> + max = nr;
> + }
> + vt->max_mem_section_nr = max;
> + return;
> + }
> +
> fprintf(fp, "\n");
> pad_line(fp, BITS32() ? 59 : 67, '-');
> fprintf(fp, "\n\nNR %s %s %s PFN\n",
>
>
> Now, with respect to the architecture-specific, VMEMMAP-only, part
> that is of most interest to you, let's do it with an architecture
> specific callback. You can post it for x86_64, and the other architecture
> maintainers can write their own version. For example, add a new
> callback function to the machdep_table structure, i.e., like this:
>
> struct machdep_table {
> ulong flags;
> ulong kvbase;
> ...
> void (*get_irq_affinity)(int);
> void (*show_interrupts)(int, ulong *);
> + int is_page_ptr(ulong, physaddr_t *);
> };
>
> Write the x86_64_is_page_ptr() function that works for VMEMMAP
> kernels, and returns FALSE otherwise. And add the call to the top
> of is_page_ptr() like this:
>
> int
> is_page_ptr(ulong addr, physaddr_t *phys)
> {
> int n;
> ulong ppstart, ppend;
> struct node_table *nt;
> ulong pgnum, node_size;
> ulong nr, sec_addr;
> ulong nr_mem_sections;
> ulong coded_mem_map, mem_map, end_mem_map;
> physaddr_t section_paddr;
>
> + if (machdep->is_page_ptr(addr, phys))
> + return TRUE;
>
> if (IS_SPARSEMEM()) {
> ...
>
> To avoid having to check whether the machdep->is_page_ptr function
> exists, write a generic_is_page_ptr() function that just returns
> FALSE, and initialize machdep->is_page_ptr to generic_is_page_ptr in
> the setup_environment() function. Later on, individual architectures
> can overwrite it when machdep_init(SETUP_ENV) is called.
>
> How's that sound?
It looks readable and refined.
If an incoming address is not a page address, the IS_SPARSEMEM() section
is also executed, but I think that it does not matter because it is rare
that the situation occurs many times at once and it is likely that the code
will become ugly to avoid it.
So I'll prepare the x86_64 part based on the above.
I thought that you would merge the common part, but is it wrong?
Could I post it with the x86_64 part?
Sorry I didn't understand well how to proceed with this.
And thank you very much for your help with this issue!
Kazuhito Hagio
Thanks,
Kazuhito Hagio
>
> Dave
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
>
https://www.redhat.com/mailman/listinfo/crash-utility
>
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility