[PATCH 1/3] kernelscan: speed up parser using hash lookup, add more print funcs
Colin King
colin.king at canonical.com
Wed Apr 27 09:53:36 UTC 2016
From: Colin Ian King <colin.king at canonical.com>
Adding a hash lookup that is self optimizing to a 1-to-1 lookup on
a larger range of kernel print functions not only speeds up the parsing
function comparison, but also allows us to add more functions to compare
with for a broader search.
Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
src/utilities/kernelscan.c | 176 +++++++++++++++++++++++++++++++++++----------
1 file changed, 138 insertions(+), 38 deletions(-)
diff --git a/src/utilities/kernelscan.c b/src/utilities/kernelscan.c
index 516577c..3a78ff7 100644
--- a/src/utilities/kernelscan.c
+++ b/src/utilities/kernelscan.c
@@ -109,8 +109,102 @@ typedef struct {
*/
static klog_pattern *patterns;
+static unsigned int hash_size;
+
+static char *funcs[] = {
+ "printk",
+ "printf",
+ "early_printk",
+ "vprintk_emit",
+ "vprintk",
+ "printk_emit",
+ "printk_once",
+ "printk_deferred",
+ "printk_deferred_once",
+ "pr_emerg",
+ "pr_alert",
+ "pr_crit",
+ "pr_err",
+ "pr_warning",
+ "pr_warn",
+ "pr_notice",
+ "pr_info",
+ "pr_cont",
+ "pr_devel",
+ "pr_debug",
+ "pr_emerg_once",
+ "pr_alert_once",
+ "pr_crit_once",
+ "pr_err_once",
+ "pr_warning_once",
+ "pr_warn_once",
+ "pr_notice_once",
+ "pr_info_once",
+ "pr_cont_once",
+ "pr_devel_once",
+ "pr_debug_once",
+ "dynamic_pr_debug",
+ "dev_vprintk_emit",
+ "dev_printk_emit",
+ "dev_printk",
+ "dev_emerg",
+ "dev_alert",
+ "dev_crit",
+ "dev_err",
+ "dev_warn",
+ "dev_dbg",
+ "dev_notice",
+ "dev_level_once",
+ "dev_emerg_once",
+ "dev_alert_once",
+ "dev_crit_once",
+ "dev_err_once",
+ "dev_warn_once",
+ "dev_notice_once",
+ "dev_info_once",
+ "dev_dbg_once",
+ "dev_level_ratelimited",
+ "dev_emerg_ratelimited",
+ "dev_alert_ratelimited",
+ "dev_crit_ratelimited",
+ "dev_err_ratelimited",
+ "dev_warn_ratelimited",
+ "dev_notice_ratelimited",
+ "dev_info_ratelimited",
+ "dbg",
+ "ACPI_ERROR",
+ "ACPI_INFO",
+ "ACPI_WARNING",
+ "ACPI_EXCEPTION",
+ "ACPI_BIOS_WARNING",
+ "ACPI_BIOS_ERROR",
+ "ACPI_ERROR_METHOD",
+ /*
+ "ACPI_DEBUG_PRINT",
+ "ACPI_DEBUG_PRINT_RAW",
+ "DEBUG",
+ */
+ NULL
+};
+
+#define TABLE_SIZE (5000)
+
+static char *hash_funcs[TABLE_SIZE];
+
static int get_token(parser *p, token *t);
+static inline unsigned int djb2a(const char *str)
+{
+ register unsigned int hash = 5381;
+ register unsigned int c;
+
+ while ((c = *str++)) {
+ /* (hash * 33) ^ c */
+ hash = ((hash << 5) + hash) ^ c;
+ }
+ return hash;
+}
+
/*
* Initialise the parser
*/
@@ -784,21 +878,10 @@ static char *strdupcat(char *old, char *new)
static int parse_kernel_message(parser *p, token *t)
{
bool got_string = false;
- bool emit = false;
bool found = false;
token_type prev_token_type = TOKEN_UNKNOWN;
char *str = NULL;
char *line = NULL;
- bool printk;
-
- printk = (strcmp(t->token, "printk") == 0);
-
- if ((strcmp(t->token, "dev_err") == 0) ||
- (strcmp(t->token, "ACPI_ERROR") == 0) ||
- (strcmp(t->token, "ACPI_BIOS_ERROR") == 0) ||
- (strcmp(t->token, "ACPI_EXCEPTION") == 0) ||
- (strcmp(t->token, "ACPI_ERROR_METHOD") == 0))
- emit = true;
line = strdupcat(line, t->token);
token_clear(t);
@@ -815,32 +898,16 @@ static int parse_kernel_message(parser *p, token *t)
* Hit ; so lets push out what we've parsed
*/
if (t->type == TOKEN_TERMINAL) {
- if (emit) {
- if (found) {
- printf("OK : %s\n", line);
- } else {
- printf("ADD: %s\n", line);
- }
+ if (found) {
+ printf("OK : %s\n", line);
+ } else {
+ printf("ADD: %s\n", line);
}
free(line);
free(str);
return PARSER_OK;
}
- /*
- * We are only interested in KERN_ERR
- * printk messages
- */
- if (printk &&
- (t->type == TOKEN_IDENTIFIER) &&
- (prev_token_type == TOKEN_PAREN_OPENED) &&
- ((strcmp(t->token, "KERN_ERR") == 0) ||
- (strcmp(t->token, "KERN_CRIT") == 0) ||
- (strcmp(t->token, "KERN_EMERG") == 0) ||
- (strcmp(t->token, "KERN_WARNING") == 0))) {
- emit = true;
- }
-
if (t->type == TOKEN_LITERAL_STRING) {
literal_strip_quotes(t);
str = strdupcat(str, t->token);
@@ -877,6 +944,14 @@ static int parse_kernel_message(parser *p, token *t)
free(line);
}
+static bool hash_find(char *token)
+{
+ unsigned int h = djb2a(token) % hash_size;
+ char *hf = hash_funcs[h];
+
+ return (hf && !strcmp(token, hf));
+}
+
/*
* Parse input looking for printk or dev_err calls
*/
@@ -892,14 +967,9 @@ static void parse_kernel_messages(FILE *fp)
token_new(&t);
while ((get_token(&p, &t)) != EOF) {
- if ((strcmp(t.token, "printk") == 0) ||
- (strcmp(t.token, "dev_err") == 0) ||
- (strcmp(t.token, "ACPI_ERROR") == 0) ||
- (strcmp(t.token, "ACPI_BIOS_ERROR") == 0) ||
- (strcmp(t.token, "ACPI_EXCEPTION") == 0) ||
- (strcmp(t.token, "ACPI_ERROR_METHOD") == 0)) {
+ if (hash_find(t.token))
parse_kernel_message(&p, &t);
- } else
+ else
token_clear(&t);
}
@@ -992,6 +1062,35 @@ static int parse_cpp_includes(FILE *fp)
return EOF;
}
+
+static void hash_init(void)
+{
+ size_t i;
+
+ /* Find optimal hash table size */
+ for (hash_size = 50; hash_size < TABLE_SIZE; hash_size++) {
+ bool collision = false;
+
+ memset(hash_funcs, 0, sizeof(hash_funcs));
+
+ for (i = 0; funcs[i]; i++) {
+ unsigned int h = djb2a(funcs[i]) % hash_size;
+
+ if (hash_funcs[h]) {
+ collision = true;
+ break;
+ }
+ hash_funcs[h] = funcs[i];
+ }
+ if (!collision)
+ break;
+ }
+ if (hash_size == TABLE_SIZE) {
+ fprintf(stderr, "Increase TABLE_SIZE for hash table\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
/*
* Scan kernel source for printk KERN_ERR and dev_err
* calls.
@@ -1025,6 +1124,7 @@ int main(int argc, char **argv)
*/
if (strcmp(argv[1], "-P") == 0) {
patterns = klog_load("firmware_error_warning_patterns");
+ hash_init();
parse_kernel_messages(stdin);
klog_free(patterns);
}
--
2.7.4
More information about the fwts-devel
mailing list