summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/nvgpu_debug_hal.py123
-rwxr-xr-xscripts/rfr233
2 files changed, 356 insertions, 0 deletions
diff --git a/scripts/nvgpu_debug_hal.py b/scripts/nvgpu_debug_hal.py
new file mode 100755
index 00000000..a56d66e3
--- /dev/null
+++ b/scripts/nvgpu_debug_hal.py
@@ -0,0 +1,123 @@
1#!/usr/bin/env python3
2#
3# Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms and conditions of the GNU General Public License,
7# version 2, as published by the Free Software Foundation.
8#
9# This program is distributed in the hope it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12# more details.
13#
14# usage: nvgpu_debug_hal.py [-h] [--csv] [--gk20a GK20A] [gops_filename]
15#
16# Analyze the HAL debugfs interface's output. With no arguments, prints out
17# statistics on the gpu_ops struct based on analysis of gk20a.h
18#
19# positional arguments:
20# gops_filename debugfs interface output file (from /d/gpu.0/hal/gops)
21#
22# optional arguments:
23# -h, --help show this help message and exit
24# --csv csv formatted output
25# --gk20a GK20A path to gk20a.h
26
27import argparse
28import re
29from os import environ
30
31description_str = ('Analyze the HAL debugfs interface\'s output. '
32'With no arguments, prints out statistics on the gpu_ops struct based on '
33'analysis of gk20a.h')
34
35parser = argparse.ArgumentParser(description=description_str);
36parser.add_argument("--csv", help="csv formatted output", action="store_true");
37parser.add_argument("--gk20a", help="path to gk20a.h");
38parser.add_argument("gops_filename", help="debugfs interface output file (from /d/gpu.0/hal/gops)", nargs='?');
39args = parser.parse_args();
40
41if args.gk20a:
42 gk20a_h_path = args.gk20a
43else:
44 top = environ.get('TOP');
45 if top is None:
46 print("$TOP is undefined, unable to find gk20a.h");
47 exit(-1);
48 gk20a_h_path = top + "/kernel/nvgpu/drivers/gpu/nvgpu/gk20a/gk20a.h"
49
50def get_function_pointer_name(line):
51 matches = re.search('.*\(\*(?P<function_name>\w+)\)\(', line);
52 if matches is None:
53 return None
54 else:
55 return matches.group("function_name");
56
57# Build the list of gpu_ops member function pointers from gk20a.h
58non_function_pointer_members = [];
59formatted_members = [];
60gops_members = dict();
61substruct_names = [];
62lone_members = [];
63with open(gk20a_h_path) as gk20a_h:
64 # Skip to start of gpu_ops struct
65 while gk20a_h.readline() != "struct gpu_ops {\n":
66 continue;
67
68 line = gk20a_h.readline();
69 while line != "};\n":
70 # If this is a substruct
71 if re.match('\t+struct.+\{', line):
72 # Read the contents of the substruct
73 line = gk20a_h.readline();
74 struct_contents = ""
75 while not re.match("\t*\} (\w+);", line):
76 struct_contents += line;
77 line = gk20a_h.readline();
78 # Split out the substruct name and the function pointer names
79 struct_name = re.match("\t*\} (?P<struct_name>\w+);", line).group("struct_name");
80 struct_members = re.findall(r".+?\(\s*\*\s*(\w+)\s*\).+?;", struct_contents, flags=re.DOTALL)
81
82 # Store the substruct as an entry
83 substruct_names.append(struct_name);
84 gops_members[struct_name] = struct_members;
85 # Format members
86 for member in struct_members:
87 formatted_members.append(struct_name + "." + member);
88 else:
89 # Lone members (function pointers or stuff not in a substruct)
90 match = re.match(".*\(\*(?P<function_name>\w+)\)\(", line);
91 if match is not None:
92 # It's a function pointer, keep track of it
93 lone_members.append(match.group("function_name"));
94 formatted_members.append(match.group("function_name"));
95 else:
96 # Not a function pointer, may also catch comments etc.
97 non_function_pointer_members.append(line.strip());
98 line = gk20a_h.readline();
99if args.gops_filename:
100 # Interpret gops file
101 with open(args.gops_filename) as gops:
102 i = 0;
103 # Option for csv output
104 if args.csv:
105 format_string = '{0},{1}';
106 else:
107 format_string = '{0:<60} = {1}';
108 for line in gops:
109 print(format_string.format(formatted_members[i], line[:-1]));
110 i += 1;
111else:
112 # Just print some stats on the gpu_ops struct
113 total = 0;
114 print("----- Lone Function Pointers -----");
115 print("Count =", len(lone_members));
116 total += len(lone_members);
117 for line in lone_members:
118 print(line);
119 print("----- Substruct Counts -----");
120 for name in substruct_names:
121 print(name, "=", len(gops_members[name]));
122 total += len(gops_members[name])
123 print("\n Total =", total);
diff --git a/scripts/rfr b/scripts/rfr
new file mode 100755
index 00000000..bca32d3b
--- /dev/null
+++ b/scripts/rfr
@@ -0,0 +1,233 @@
1#!/usr/bin/python
2#
3# Simple script for formatting RFR messages for nvgpu changes.
4#
5
6import os
7import re
8import json
9import argparse
10import subprocess
11
12VERSION = '1.0.0'
13
14# Gerrit commit URL formats. These are regular expressions to match the
15# incoming URLs against.
16gr_fmts = [ r'http://git-master/r/(\d+)',
17 r'http://git-master/r/#/c/(\d+)/',
18 r'http://git-master.nvidia.com/r/(\d+)',
19 r'http://git-master.nvidia.com/r/#/c/(\d+)/',
20 r'https://git-master/r/(\d+)',
21 r'https://git-master/r/#/c/(\d+)/',
22 r'https://git-master.nvidia.com/r/(\d+)',
23 r'https://git-master.nvidia.com/r/#/c/(\d+)/' ]
24
25# The user to use. May be overridden but the default comes from the environment.
26user = os.environ['USER']
27
28# Gerrit query command to obtain the patch URL. The substitution will be the
29# gerrit Change-ID parsed from the git commit message.
30gr_query_cmd = 'ssh %s@git-master -p 29418 gerrit query --format json %s'
31
32def parse_args():
33 """
34 Parse arguments to rfr.
35 """
36
37 ep="""This program will format commit messages into something that can be
38sent to the nvgpu mailing list for review
39"""
40 help_msg="""Git or gerrit commits to describe. Can be either a git or gerrit
41commit ID. If the ID starts with a 'I' then it will be treated as a gerrit ID.
42If the commit ID looks like a gerrit URL then it is treated as a gerrit URL.
43Otherwise it's treated as a git commit ID.
44"""
45 parser = argparse.ArgumentParser(description='RFR formatting tool',
46 epilog=ep)
47
48 parser.add_argument('-V', '--version', action='store_true', default=False,
49 help='print the program version')
50 parser.add_argument('-m', '--msg', action='store', default=None,
51 help='Custom message to add to the RFR email')
52
53 # Positionals: the gerrit URLs.
54 parser.add_argument('commits', metavar='Commit-IDs',
55 nargs='+',
56 help=help_msg)
57
58 arg_parser = parser.parse_args()
59
60 return arg_parser
61
62def get_gerrit_url_id(cmt):
63 """
64 Determines if the passed cmt is a gerrit commit URL. If it is then this
65 returns the URL ID; otherwise it returns None.
66 """
67
68 for fmt in gr_fmts:
69 p = re.compile(fmt)
70 m = p.search(cmt)
71 if m:
72 return m.group(1)
73
74 return None
75
76def gerrit_query(change):
77 """
78 Query gerrit for the JSON change information. Return a python object
79 describing the JSON data.
80
81 change can either be a Change-Id or the numeric change number from a URL.
82
83 Note there is an interesting limitation with this: gerrit can have multiple
84 changes with the same Change-Id (./sigh). So if you query a change ID that
85 points to multiple changes you get back all of them.
86
87 This script just uses the first. Ideally one could filter by branch or by
88 some other distinguishing factor.
89 """
90
91 query_cmd = gr_query_cmd % (user, change)
92
93 prog = subprocess.Popen(query_cmd, shell=True,
94 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
95
96 stdout_data, stderr_data = prog.communicate()
97 if prog.returncode != 0:
98 print('`%s\' failed!' % query_cmd)
99 return False
100
101 commit = json.loads(stdout_data.decode('utf-8').splitlines()[0])
102 if 'id' not in commit:
103 print('%s is not a gerrit commit!?' % change)
104 print('Most likely you need to push the change.')
105 return None
106
107 return commit
108
109def commit_info_from_gerrit_change_id(change_id):
110 """
111 Return a dict with all the gerrit info from a gerrit change ID.
112 """
113
114 return gerrit_query(change_id)
115
116def commit_info_from_git_sha1(rev):
117 """
118 Return a dict with all the gerrit info from a git sha1 rev.
119 """
120
121 return gerrit_query(rev)
122
123def commit_info_from_gerrit_cl(cmt):
124 """
125 Return a dict with all the gerrit info from a Gerrit URL.
126 """
127
128 cl = get_gerrit_url_id(cmt)
129 if not cl:
130 return None
131
132 return gerrit_query(cl)
133
134def git_sha1_from_commit(commit_ish):
135 """
136 Return sha1 revision from a commit-ish string, or None if this doesn't
137 appear to be a commit.
138 """
139
140 prog = subprocess.Popen('git rev-parse %s' % commit_ish, shell=True,
141 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
142
143 stdout_data, stderr_data = prog.communicate()
144 if prog.returncode != 0:
145 print('`git rev-parse %s\' failed?!' % commit_ish)
146 return None
147
148 return stdout_data.decode('utf-8')
149
150def indent_lines(text, ind):
151 """
152 Prepend each new line in the passed text with ind.
153 """
154 return ''.join(ind + l + '\n' for l in text.splitlines())
155
156def display_commits(commits_info, extra_message):
157 """
158 Takes a list of the commit info objects to print.
159 """
160
161 whole_template = """
162Hi All,
163
164I would like you to review the following changes.
165{extra_message}
166{cmt_descriptions}
167Thanks!
168{cmt_verbose}"""
169
170 cmt_template = """
171+----------------------------------------
172| {url}
173| Author: {author}
174
175{cmtmsg}"""
176
177 cmt_descriptions = ''
178 for c in commits_info:
179 cmt_descriptions += " %s - %s\n" % (c['url'], c['subject'])
180
181 # Add new lines around the extra_message, if applicable. Otherwise we don't
182 # want anything to show up for extra_message.
183 if extra_message:
184 extra_message = '\n%s\n' % extra_message
185 else:
186 extra_message = ''
187
188 cmt_verbose = ''
189 for c in commits_info:
190 cmt_verbose += cmt_template.format(url=c['url'],
191 author=c['owner']['name'],
192 cmtmsg=indent_lines(
193 c['commitMessage'], ' '))
194
195 print(whole_template.format(cmt_descriptions=cmt_descriptions,
196 extra_message=extra_message,
197 cmt_verbose=cmt_verbose))
198
199def main():
200 """
201 The magic happens here.
202 """
203
204 arg_parser = parse_args()
205 commits_info = [ ]
206
207 if arg_parser.version:
208 print('Version: %s' % VERSION)
209 exit(0)
210
211 # Builds a dictionary of Gerrit Change-Ids. From the Change-Ids we can then
212 # get the commit message and URL.
213 #
214 # This also builds an array of those same commit IDs to track the ordering
215 # of the commits so that the user can choose the order of the patches based
216 # on the order in which they pass the commits.
217 for cmt in arg_parser.commits:
218 if cmt[0] == 'I':
219 info = commit_info_from_gerrit_change_id(cmt)
220 elif get_gerrit_url_id(cmt):
221 info = commit_info_from_gerrit_cl(cmt)
222 else:
223 info = commit_info_from_git_sha1(git_sha1_from_commit(cmt))
224
225 if info:
226 commits_info.append(info)
227 else:
228 print('Warning: \'%s\' doesn\'t appear to be a commit!' % cmt)
229
230 display_commits(commits_info, arg_parser.msg)
231
232if __name__ == '__main__':
233 main()