diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-01-19 17:17:40 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-01-19 17:22:36 +0100 |
| commit | 891b46a9a5a32dba986a8ba7e08d9192a2f9d894 (patch) | |
| tree | d1f1e998cba1ee04c14a14e5e7f8a03af0814516 /vm | |
| parent | dfd341e3493321cb5de483efe7b2d78877aef344 (diff) | |
vm: faster output oops grepping
Use manual parsing instead of a regexp.
Regexp takes ~220ms for typical output size. New code takes ~2ms.
Brings manager CPU consumption from ~250% down to ~25%.
Diffstat (limited to 'vm')
| -rw-r--r-- | vm/vm.go | 49 | ||||
| -rw-r--r-- | vm/vm_test.go | 21 |
2 files changed, 54 insertions, 16 deletions
@@ -4,9 +4,9 @@ package vm import ( + "bytes" "errors" "fmt" - "regexp" "time" ) @@ -60,9 +60,50 @@ func Create(typ string, cfg *Config) (Instance, error) { return ctor(cfg) } +// FindCrash searches kernel console output for oops messages. +// Desc contains a more-or-less representative description of the first oops, +// start and end denote region of output with oops message(s). +func FindCrash(output []byte) (desc string, start int, end int, found bool) { + for pos := 0; pos < len(output); { + next := bytes.IndexByte(output[pos:], '\n') + if next != -1 { + next += pos + } else { + next = len(output) + } + for _, oops := range oopses { + match := bytes.Index(output[pos:next], oops) + if match == -1 { + continue + } + if !found { + found = true + start = pos + desc = string(output[pos+match : next]) + if desc[len(desc)-1] == '\r' { + desc = desc[:len(desc)-1] + } + } + end = next + } + pos = next + 1 + } + return +} + var ( - CrashRe = regexp.MustCompile("Kernel panic[^\r\n]*|BUG:[^\r\n]*|kernel BUG[^\r\n]*|WARNING:[^\r\n]*|" + - "INFO:[^\r\n]*|unable to handle|Unable to handle kernel[^\r\n]*|general protection fault|UBSAN:[^\r\n]*|" + - "unreferenced object[^\r\n]*") + oopses = [][]byte{ + []byte("Kernel panic"), + []byte("BUG:"), + []byte("kernel BUG"), + []byte("WARNING:"), + []byte("INFO:"), + []byte("unable to handle"), + []byte("Unable to handle kernel"), + []byte("general protection fault"), + []byte("UBSAN:"), + []byte("unreferenced object"), + } + TimeoutErr = errors.New("timeout") ) diff --git a/vm/vm_test.go b/vm/vm_test.go index 896db8e57..d83ad98fa 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestCrashRe(t *testing.T) { +func TestFindCrash(t *testing.T) { tests := map[string]string{ ` [ 50.583499] something @@ -23,7 +23,7 @@ func TestCrashRe(t *testing.T) { ` [ 50.583499] general protection fault: 0000 [#1] SMP KASAN [ 50.583499] Modules linked in: -`: "general protection fault", +`: "general protection fault: 0000 [#1] SMP KASAN", ` [ 50.583499] BUG: unable to handle kernel NULL pointer dereference at 000000000000003a [ 50.583499] Modules linked in: @@ -82,19 +82,16 @@ locks_free_lock_context+0x118/0x180() tests[strings.Replace(log, "\n", "\r\n", -1)] = crash } for log, crash := range tests { - loc := CrashRe.FindStringIndex(log) - if loc == nil && crash != "" { + desc, _, _, found := FindCrash([]byte(log)) + //t.Logf("%v\nexpect '%v', found '%v'\n", log, crash, desc) + if !found && crash != "" { t.Fatalf("did not find crash message '%v' in:\n%v", crash, log) } - if loc != nil && crash == "" { - t.Fatalf("found bogus crash message '%v' in:\n%v", log[loc[0]:loc[1]], log) + if found && crash == "" { + t.Fatalf("found bogus crash message '%v' in:\n%v", desc, log) } - if loc == nil { - continue - } - crash1 := log[loc[0]:loc[1]] - if crash1 != crash { - t.Fatalf("extracted bad crash message:\n%v\nwant:\n%v", crash1, crash) + if desc != crash { + t.Fatalf("extracted bad crash message:\n%v\nwant:\n%v", desc, crash) } } } |
