From 6e1c7e48b62e3d25d667dfa47340cbe5f2e613e9 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Fri, 18 Oct 2019 09:56:15 +0200 Subject: [PATCH] Donate cpu server crash locations (#2276) donate-cpu-server: Print grouped stack traces in crash report Example output: Packages: psi xenomai Token::hasKnownValue (this=0x0) at lib/token.h:988 988 return mImpl->mValues && std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); #0 Token::hasKnownValue (...) at lib/token.h:988 #1 valueFlowReverse (...) at build/valueflow.cpp:3775 #2 valueFlowBeforeCondition (...) at /usr/include/c++/8/bits/stl_list.h:301 #3 ValueFlow::setValues (...) at build/valueflow.cpp:8403 #4 Tokenizer::simplifyTokens1 (...) at build/tokenize.cpp:11095 #5 CppCheck::checkFile (...) at build/cppcheck.cpp:513 #6 CppCheck::check (...) at /usr/include/c++/8/bits/basic_string.h:936 #7 CppCheckExecutor::check_internal (...) at cli/cppcheckexecutor.cpp:884 #8 CppCheckExecutor::check (...) at cli/cppcheckexecutor.cpp:198 #9 main (...) at cli/main.cpp:95 Packages: broker valueFlowReverse (tokenlist=tokenlist@entry=0x7fffffffbce0, tok=tok@entry=0x555555cc9930, varToken=varToken@entry=0x555555cc9b70, val=..., val2=..., errorLogger=errorLogger@entry=0x7fffffffcb20, settings=0x7fffffffcd40) at build/valueflow.cpp:3775 3775 if (!assignTok->hasKnownValue()) { #0 valueFlowReverse (...) at build/valueflow.cpp:3775 #1 valueFlowBeforeCondition (...) at build/valueflow.cpp:4092 #2 ValueFlow::setValues (...) at build/valueflow.cpp:8406 #3 Tokenizer::simplifyTokens1 (...) at build/tokenize.cpp:11095 #4 CppCheck::checkFile (...) at build/cppcheck.cpp:513 #5 CppCheck::check (...) at build/cppcheck.cpp:197 #6 CppCheckExecutor::check_internal (...) at cli/cppcheckexecutor.cpp:884 #7 CppCheckExecutor::check (...) at cli/cppcheckexecutor.cpp:198 #8 main (...) at cli/main.cpp:95 --- tools/donate-cpu-server.py | 98 +++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py index a8894d382..c52f379b5 100644 --- a/tools/donate-cpu-server.py +++ b/tools/donate-cpu-server.py @@ -18,7 +18,7 @@ import operator # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/ # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic # changes) -SERVER_VERSION = "1.1.6" +SERVER_VERSION = "1.1.7" OLD_VERSION = '1.89' @@ -76,7 +76,7 @@ def overviewReport(): return html -def fmt(a, b, c, d, e): +def fmt(a, b, c=None, d=None, e=None, link=True): column_width = [40, 10, 5, 6, 6, 8] ret = a while len(ret) < column_width[0]: @@ -86,14 +86,15 @@ def fmt(a, b, c, d, e): while len(ret) < (column_width[0] + 1 + column_width[1]): ret += ' ' ret += ' ' - ret += b[-5:].rjust(column_width[2]) + ' ' + if len(b) > 10: + ret += b[-5:].rjust(column_width[2]) + ' ' if not c is None: ret += c.rjust(column_width[3]) + ' ' if not d is None: ret += d.rjust(column_width[4]) + ' ' if not e is None: ret += e.rjust(column_width[5]) - if a != 'Package': + if link: pos = ret.find(' ') ret = '' + a + '' + ret[pos:] return ret @@ -102,7 +103,7 @@ def fmt(a, b, c, d, e): def latestReport(latestResults): html = 'Latest daca@home results\n' html += '

Latest daca@home results

\n' - html += '
\n' + fmt('Package', 'Date       Time', OLD_VERSION, 'Head', 'Diff') + '\n'
+    html += '
\n' + fmt('Package', 'Date       Time', OLD_VERSION, 'Head', 'Diff', link=False) + '\n'
 
     # Write report for latest results
     for filename in latestResults:
@@ -142,37 +143,70 @@ def crashReport(results_path):
     html = 'Crash report\n'
     html += '

Crash report

\n' html += '
\n'
-    html += '' + fmt('Package', 'Date       Time', OLD_VERSION, 'Head', None) + '\n'
+    html += '' + fmt('Package', 'Date       Time', OLD_VERSION, 'Head', link=False) + '\n'
     current_year = datetime.date.today().year
+    stack_traces = {}
     for filename in sorted(glob.glob(os.path.expanduser(results_path + '/*'))):
         if not os.path.isfile(filename):
             continue
         datestr = ''
-        for line in open(filename, 'rt'):
-            line = line.strip()
-            if line.startswith('cppcheck: '):
-                if OLD_VERSION not in line:
-                    # Package results seem to be too old, skip
+        with open(filename, 'rt') as file:
+            for line in file:
+                line = line.strip()
+                if line.startswith('cppcheck: '):
+                    if OLD_VERSION not in line:
+                        # Package results seem to be too old, skip
+                        break
+                    else:
+                        # Current package, parse on
+                        continue
+                if line.startswith(str(current_year) + '-') or line.startswith(str(current_year - 1) + '-'):
+                    datestr = line
+                if line.startswith('count:'):
+                    if line.find('Crash') < 0:
+                        break
+                    package = filename[filename.rfind('/')+1:]
+                    counts = line.strip().split(' ')
+                    c2 = ''
+                    if counts[2] == 'Crash!':
+                        c2 = 'Crash'
+                    c1 = ''
+                    if counts[1] == 'Crash!':
+                        c1 = 'Crash'
+                    html += fmt(package, datestr, c2, c1) + '\n'
+                    if c1 != 'Crash':
+                        break
+                if line.find(' received signal ') != -1:
+                    crash_line = next(file, '').strip()
+                    location_index = crash_line.rindex(' at ')
+                    if location_index > 0:
+                        code_line = next(file, '').strip();
+                        stack_trace = []
+                        while True:
+                            l = next(file, '')
+                            m = re.search(r'(?P#\d+) .* (?P.+)\(.*\) at (?P.*)$', l)
+                            if not m:
+                                break
+                            stack_trace.append(m.group('number') + ' ' + m.group('function') + '(...) at ' + m.group('location'))
+                        key = hash(' '.join(stack_trace))
+
+                        if key in stack_traces:
+                            stack_traces[key]['code_line'] = code_line
+                            stack_traces[key]['stack_trace'] = stack_trace
+                            stack_traces[key]['n'] += 1
+                            stack_traces[key]['packages'].append(package)
+                        else:
+                            stack_traces[key] = {'stack_trace': stack_trace, 'n': 1, 'code_line': code_line, 'packages': [package], 'crash_line': crash_line}
                     break
-                else:
-                    # Current package, parse on
-                    continue
-            if line.startswith(str(current_year) + '-') or line.startswith(str(current_year - 1) + '-'):
-                datestr = line
-            if not line.startswith('count:'):
-                continue
-            if line.find('Crash') < 0:
-                break
-            package = filename[filename.rfind('/')+1:]
-            counts = line.strip().split(' ')
-            c2 = ''
-            if counts[2] == 'Crash!':
-                c2 = 'Crash'
-            c1 = ''
-            if counts[1] == 'Crash!':
-                c1 = 'Crash'
-            html += fmt(package, datestr, c2, c1, None) + '\n'
-            break
+
+    html += '
\n' + html += '
\n'
+    html += 'Stack traces\n'
+    for stack_trace in sorted(stack_traces.values(), key=lambda x: x['n'], reverse=True):
+        html += 'Packages: ' + ' '.join(['' + p + '' for p in stack_trace['packages']]) + '\n'
+        html += stack_trace['crash_line'] + '\n'
+        html += stack_trace['code_line'] + '\n'
+        html += '\n'.join(stack_trace['stack_trace']) + '\n\n'
     html += '
\n' html += '\n' @@ -183,7 +217,7 @@ def staleReport(results_path): html = 'Stale report\n' html += '

Stale report

\n' html += '
\n'
-    html += '' + fmt('Package', 'Date       Time', None, None, None) + '\n'
+    html += '' + fmt('Package', 'Date       Time', link=False) + '\n'
     current_year = datetime.date.today().year
     for filename in sorted(glob.glob(os.path.expanduser(results_path + '/*'))):
         if not os.path.isfile(filename):
@@ -199,7 +233,7 @@ def staleReport(results_path):
             if diff.days < 30:
                 continue
             package = filename[filename.rfind('/')+1:]
-            html += fmt(package, datestr, None, None, None) + '\n'
+            html += fmt(package, datestr) + '\n'
             break
     html += '
\n'