Increase the internal hash queue head count from 128 to 32768.

The hash queue is used for gathering and verifying lists, and the
original count of 128 may be overwhelmed if a list is extremely
large.  For example, on a 256GB system with 192GB of free pages,
the "kmem -f" command takes hours to complete; with this patch,
the time is reduced to a few minutes.  In addition, a new command
line option "--hash <count>" has been added to allow a user to
override the default hash queue head count of 32768.
(anderson@redhat.com)
This commit is contained in:
Dave Anderson 2014-03-13 11:56:30 -04:00
parent dc7fea0128
commit 5645af9598
5 changed files with 39 additions and 11 deletions

View File

@ -463,6 +463,10 @@ value that is larger than its
value, then it will be necessary to enter
a relocation size equal to the difference between the two values.
.TP
.BI --hash \ count
Set the number of internal hash queue heads used for list gathering
and verification. The default count is 32768.
.TP
.B --minimal
Bring up a session that is restricted to the
.I log, dis, rd, sym, eval, set

1
defs.h
View File

@ -513,6 +513,7 @@ struct program_context {
void (*cmd_cleanup)(void *); /* per-command cleanup function */
void *cmd_cleanup_arg; /* optional cleanup function argument */
ulong scope; /* optional text context address */
ulong nr_hash_queues; /* hash queue head count */
};
#define READMEM pc->readmem

4
help.c
View File

@ -297,6 +297,10 @@ char *program_usage_info[] = {
" be necessary to enter a relocation size equal to the difference between",
" the two values.",
"",
" --hash count",
" Set the number of internal hash queue heads used for list gathering",
" and verification. The default count is 32768.",
"",
" --kaslr offset | auto",
" If an x86_64 kernel was configured with CONFIG_RANDOMIZE_BASE, the",
" offset value is equal to the difference between the symbol values ",

9
main.c
View File

@ -69,6 +69,7 @@ static struct option long_options[] = {
{"hex", 0, 0, 0},
{"dec", 0, 0, 0},
{"no_strip", 0, 0, 0},
{"hash", required_argument, 0, 0},
{0, 0, 0, 0}
};
@ -217,7 +218,12 @@ main(int argc, char **argv)
else if (STREQ(long_options[option_index].name, "mod"))
kt->module_tree = optarg;
else if (STREQ(long_options[option_index].name, "kaslr")) {
else if (STREQ(long_options[option_index].name, "hash")) {
if (!calculate(optarg, &pc->nr_hash_queues, NULL, 0)) {
error(INFO, "invalid --hash argument: %s\n",
optarg);
}
} else if (STREQ(long_options[option_index].name, "kaslr")) {
if (!machine_type("X86_64"))
error(INFO, "--kaslr only valid "
"with X86_64 machine type.\n");
@ -1594,6 +1600,7 @@ dump_program_context(void)
fprintf(fp, " cleanup: %s\n", pc->cleanup);
fprintf(fp, " scope: %lx %s\n", pc->scope,
pc->scope ? "" : "(not set)");
fprintf(fp, " nr_hash_queues: %ld\n", pc->nr_hash_queues);
}
char *

32
tools.c
View File

@ -1,8 +1,8 @@
/* tools.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2013 David Anderson
* Copyright (C) 2002-2013 Red Hat, Inc. All rights reserved.
* Copyright (C) 2002-2014 David Anderson
* Copyright (C) 2002-2014 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -4126,9 +4126,9 @@ dump_struct_members_for_tree(struct tree_data *td, int idx, ulong struct_p)
#define HASH_QUEUE_CLOSED (0x8)
#define HQ_ENTRY_CHUNK (1024)
#define NR_HASH_QUEUES (HQ_ENTRY_CHUNK/8)
#define NR_HASH_QUEUES_DEFAULT (32768UL)
#define HQ_SHIFT (machdep->pageshift)
#define HQ_INDEX(X) (((X) >> HQ_SHIFT) % NR_HASH_QUEUES)
#define HQ_INDEX(X) (((X) >> HQ_SHIFT) % pc->nr_hash_queues)
struct hq_entry {
int next;
@ -4143,7 +4143,7 @@ struct hq_head {
struct hash_table {
ulong flags;
struct hq_head queue_heads[NR_HASH_QUEUES];
struct hq_head *queue_heads;
struct hq_entry *memptr;
long count;
long index;
@ -4161,6 +4161,18 @@ hq_init(void)
ht = &hash_table;
if (pc->nr_hash_queues == 0)
pc->nr_hash_queues = NR_HASH_QUEUES_DEFAULT;
if ((ht->queue_heads = (struct hq_head *)malloc(pc->nr_hash_queues *
sizeof(struct hq_head))) == NULL) {
error(INFO, "cannot malloc memory for hash queue heads: %s\n",
strerror(errno));
ht->flags = HASH_QUEUE_NONE;
pc->flags &= ~HASH;
return;
}
if ((ht->memptr = (struct hq_entry *)malloc(HQ_ENTRY_CHUNK *
sizeof(struct hq_entry))) == NULL) {
error(INFO, "cannot malloc memory for hash queues: %s\n",
@ -4241,7 +4253,7 @@ hq_open(void)
return FALSE;
ht->flags &= ~(HASH_QUEUE_FULL|HASH_QUEUE_CLOSED);
BZERO(ht->queue_heads, sizeof(struct hq_head) * NR_HASH_QUEUES);
BZERO(ht->queue_heads, sizeof(struct hq_head) * pc->nr_hash_queues);
BZERO(ht->memptr, ht->count * sizeof(struct hq_entry));
ht->index = 0;
@ -4403,7 +4415,7 @@ dump_hash_table(int verbose)
if (ht->flags & HASH_QUEUE_FULL)
fprintf(fp, "%sHASH_QUEUE_FULL", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " queue_heads[%d]: %lx\n", NR_HASH_QUEUES,
fprintf(fp, " queue_heads[%ld]: %lx\n", pc->nr_hash_queues,
(ulong)ht->queue_heads);
fprintf(fp, " memptr: %lx\n", (ulong)ht->memptr);
fprintf(fp, " count: %ld ", ht->count);
@ -4416,7 +4428,7 @@ dump_hash_table(int verbose)
minq = ~(0);
maxq = 0;
for (i = 0; i < NR_HASH_QUEUES; i++) {
for (i = 0; i < pc->nr_hash_queues; i++) {
if (ht->queue_heads[i].next == 0) {
minq = 0;
continue;
@ -4448,8 +4460,8 @@ dump_hash_table(int verbose)
if (elements != ht->index)
fprintf(fp, " elements found: %ld (expected %ld)\n",
elements, ht->index);
fprintf(fp, " queues in use: %ld of %d\n", queues_in_use,
NR_HASH_QUEUES);
fprintf(fp, " queues in use: %ld of %ld\n", queues_in_use,
pc->nr_hash_queues);
fprintf(fp, " queue length range: %d to %d\n", minq, maxq);
if (verbose) {