Skip to content

Commit b951bcb

Browse files
authored
Merge pull request diffblue#491 from diffblue/improved_time_profiler
SEC-517: Improved time profiler
2 parents ac8d424 + ef50f40 commit b951bcb

File tree

6 files changed

+321
-85
lines changed

6 files changed

+321
-85
lines changed

driver/html_utl.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
def get_html_prefix(page_name):
2+
return ("<!DOCTYPE html>\n"
3+
"<html>\n"
4+
"<head>\n"
5+
"<title>" + page_name + "</title>\n"
6+
"<style>\n"
7+
"table, th, td {\n"
8+
" border: 1px solid black;\n"
9+
" border-collapse: collapse;\n"
10+
"}\n"
11+
"th, td {\n"
12+
" padding: 5px;\n"
13+
"}\n"
14+
"h1, h2, h3, h4, p, a, table, ul { "
15+
"font-family: \"Liberation serif\", serif; }\n"
16+
"p, a, table, ul { font-size: 12pt; }\n"
17+
"h4 { font-size: 12pt; }\n"
18+
"h3 { font-size: 14pt; }\n"
19+
"h2 { font-size: 18pt; }\n"
20+
"h1 { font-size: 24pt; }\n"
21+
"tt { font-family: \"Liberation Mono\", monospace; }\n"
22+
"tt { font-size: 10pt; }\n"
23+
"body {\n"
24+
" background-color: white;\n"
25+
" color: black;\n"
26+
"}\n"
27+
"</style>\n"
28+
"</head>\n"
29+
"<body>\n")
30+
31+
32+
def get_html_suffix():
33+
return ("</body>\n"
34+
"</html>\n")
35+
36+
37+
def escape_text_to_HTML(text):
38+
return text.replace("<", "&lt;") \
39+
.replace(">", "&gt;")
40+
41+
42+
def text_to_file_or_dir_name(text):
43+
return text.replace("#","_") \
44+
.replace("$","_") \
45+
.replace(":", ".") \
46+
.replace("/", ".") \
47+
.replace("\\", ".") \
48+
.replace("<", "[") \
49+
.replace(">", "]")

driver/presentation.py

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import json
33
import glob
44
import os
5+
from html_utl import get_html_prefix, get_html_suffix, escape_text_to_HTML, text_to_file_or_dir_name
6+
import tmprof_view
57

68

79
def __count_of_json_files_in_dir(directory):
@@ -13,56 +15,6 @@ def __count_of_json_files_in_dir(directory):
1315
return count
1416

1517

16-
def escape_text_to_HTML(text):
17-
return text.replace("<","&lt;")\
18-
.replace(">","&gt;")
19-
20-
def text_to_file_or_dir_name(text):
21-
return text.replace("#","_")\
22-
.replace("$","_") \
23-
.replace(":", ".") \
24-
.replace("/", ".") \
25-
.replace("\\", ".") \
26-
.replace("<", "[") \
27-
.replace(">", "]")
28-
29-
30-
def get_html_prefix(page_name):
31-
return ("<!DOCTYPE html>\n"
32-
"<html>\n"
33-
"<head>\n"
34-
"<title>" + page_name + "</title>\n"
35-
"<style>\n"
36-
"table, th, td {\n"
37-
" border: 1px solid black;\n"
38-
" border-collapse: collapse;\n"
39-
"}\n"
40-
"th, td {\n"
41-
" padding: 5px;\n"
42-
"}\n"
43-
"h1, h2, h3, h4, p, a, table, ul { "
44-
"font-family: \"Liberation serif\", serif; }\n"
45-
"p, a, table, ul { font-size: 12pt; }\n"
46-
"h4 { font-size: 12pt; }\n"
47-
"h3 { font-size: 14pt; }\n"
48-
"h2 { font-size: 18pt; }\n"
49-
"h1 { font-size: 24pt; }\n"
50-
"tt { font-family: \"Liberation Mono\", monospace; }\n"
51-
"tt { font-size: 10pt; }\n"
52-
"body {\n"
53-
" background-color: white;\n"
54-
" color: black;\n"
55-
"}\n"
56-
"</style>\n"
57-
"</head>\n"
58-
"<body>\n")
59-
60-
61-
def get_html_suffix():
62-
return ("</body>\n"
63-
"</html>\n")
64-
65-
6618
def build_HTML_interface_to_plots(
6719
benchmark_name,
6820
stats_plots_dir,
@@ -796,6 +748,13 @@ def build_HTML_interface_to_results_and_statistics(
796748
ofile.write(" <td>Plots showing function summarisation speed</td>\n")
797749
ofile.write(" <td><a href=\"./statistics/plots/index.html\">here</a></td>\n")
798750
ofile.write(" </tr>\n")
751+
tmprof_stats = os.path.abspath(os.path.join(cmdline.results_dir, "TMPROF.json"))
752+
if os.path.isfile(tmprof_stats):
753+
ofile.write(" <tr>\n")
754+
ofile.write(" <td>Time profile of Stage 1</td>\n")
755+
ofile.write(" <td><a href=\"./statistics/TMPROF.html\">here</a></td>\n")
756+
ofile.write(" </tr>\n")
757+
tmprof_view.generate_html(tmprof_stats, os.path.abspath(os.path.join(cmdline.results_dir, "statistics", "TMPROF.html")))
799758
ofile.write("</table>\n")
800759

801760
if cmdline.dump_html_program:

driver/tmprof_view.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import os
2+
import json
3+
import argparse
4+
import html_utl
5+
6+
7+
def get_sort_keys():
8+
return [
9+
"total_time",
10+
"max_time",
11+
"hit_count",
12+
"max_runs",
13+
"run_count",
14+
]
15+
16+
17+
def get_integer_keys():
18+
return [
19+
"hit_count",
20+
"max_runs",
21+
"run_count",
22+
]
23+
24+
25+
def get_column_names():
26+
return [
27+
"Time",
28+
"TimePeek",
29+
"#Hits",
30+
"RunPeek",
31+
"#Runs",
32+
]
33+
34+
35+
def as_html(stats, keys_order=None):
36+
if keys_order is None:
37+
keys_order = get_sort_keys()
38+
result = html_utl.get_html_prefix("TMPROF")
39+
sorted_stats = stats[:]
40+
reversed_keys_order = keys_order[:]
41+
reversed_keys_order.reverse()
42+
for key in reversed_keys_order:
43+
sorted_stats = sorted(sorted_stats, key=lambda x: x[key])
44+
sorted_stats.reverse()
45+
total_time = sum([record["total_time"] for record in sorted_stats])
46+
result += "<h2>Time profile</h2>\n"
47+
result += "<table>\n"
48+
result += " <caption>All times are in seconds.</caption>\n"
49+
result += " <tr>\n"
50+
result += " <th>#</th>\n"
51+
result += " <th>Function</th>\n"
52+
result += " <th>%</th>\n"
53+
for key in keys_order:
54+
result += " <th>" + get_column_names()[get_sort_keys().index(key)] +"</th>\n"
55+
result += " <th>File</th>\n"
56+
result += " <th>Line</th>\n"
57+
result += " </tr>\n"
58+
for idx, record in enumerate(sorted_stats):
59+
result += " <tr>\n"
60+
result += " <td>" + str(idx + 1) + "</td>\n"
61+
result += " <td>" + html_utl.escape_text_to_HTML(record["function"]) + "</td>\n"
62+
result += " <td>" + format(100.0 * record["total_time"] / (total_time + 0.0001), ".1f") + "</td>\n"
63+
for key in keys_order:
64+
if key in get_integer_keys():
65+
result += " <td>" + str(record[key]) + "</td>\n"
66+
else:
67+
result += " <td>" + format(record[key], ".3f") + "</td>\n"
68+
result += " <td>" + record["file"] + "</td>\n"
69+
result += " <td>" + str(record["line"]) + "</td>\n"
70+
result += " </tr>\n"
71+
return result + html_utl.get_html_suffix()
72+
73+
74+
def generate_html_from_stats(stats, out_html_file, keys_order=None):
75+
with open(out_html_file, "w") as ofile:
76+
ofile.write(as_html(stats, keys_order))
77+
78+
79+
def generate_html(in_json_file, out_html_file, keys_order=None):
80+
with open(in_json_file, "r") as ifile:
81+
stats = json.load(ifile)
82+
generate_html_from_stats(stats, out_html_file, keys_order)
83+
84+
85+
def _main(cmdline):
86+
if cmdline.version:
87+
print("v.1.0")
88+
return 0
89+
90+
cmdline.input = os.path.abspath(cmdline.input)
91+
if not os.path.isfile(cmdline.input):
92+
print("ERROR: Cannot access the input JSON file: " + cmdline.input)
93+
return -1
94+
if os.path.splitext(cmdline.input)[1].lower() != ".json":
95+
print("ERROR: Ihe input file does not have '.json' extension: " + cmdline.input)
96+
return -2
97+
98+
if cmdline.output is None:
99+
cmdline.output = os.path.splitext(cmdline.input)[0] + ".html"
100+
else:
101+
cmdline.output = os.path.abspath(cmdline.output)
102+
if os.path.splitext(cmdline.output)[1].lower() != ".html":
103+
print("ERROR: Ihe output file does not have '.html' extension: " + cmdline.output)
104+
return -3
105+
os.makedirs(os.path.dirname(cmdline.output), exist_ok=True)
106+
107+
if cmdline.keys is None:
108+
cmdline.keys = get_sort_keys()
109+
else:
110+
order = []
111+
if len(cmdline.keys) != len(set(cmdline.keys)):
112+
print("ERROR: The option --keys was passed duplicate keys.")
113+
return -4
114+
for key in cmdline.keys:
115+
if key not in get_sort_keys():
116+
print("ERROR: The key '" + key + "' is not valid. Use --help fro more details.")
117+
return -5
118+
order.append(key)
119+
for key in get_sort_keys():
120+
if key not in order:
121+
order.append(key)
122+
cmdline.keys = order
123+
124+
generate_html(cmdline.input, cmdline.output, cmdline.keys)
125+
# try:
126+
# generate_html(cmdline.input, cmdline.output, cmdline.keys)
127+
# except:
128+
# print("ERROR: The conversion to HTML has FAILED.")
129+
# return -6
130+
131+
return 0
132+
133+
134+
def _parse_cmd_line():
135+
parser = argparse.ArgumentParser(
136+
description="This is the security analyser of Java web applications.")
137+
parser.add_argument("-V", "--version", action="store_true",
138+
help="Prints a version string.")
139+
parser.add_argument("input", type=str,
140+
help="A path-name of a JSON file containing time profiling data.")
141+
parser.add_argument("-o", "--output", type=str,
142+
help="A path-name of an HTML file to be filled in by the time profiling data in the JSON file. "
143+
"If not specified, the HTML file (with the same name as the JSON file) will be created "
144+
"in the directory of the JSON file. In the HTML the keys corresponds to these columns "
145+
"respectively: " + ",".join(get_column_names()) + ".")
146+
parser.add_argument("-k", "--keys", nargs='+',
147+
help="An ordered list of keys defining the lexicographical order of columns in the "
148+
"HTML table. Here are the keys, listed in the default order: " +
149+
", ".join(get_sort_keys()) + ". Not specifies some keys will be appended to "
150+
"from the default order.")
151+
return parser.parse_args()
152+
153+
154+
if __name__ == "__main__":
155+
exit(_main(_parse_cmd_line()))

src/taint-analysis/taint_security_scanner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ bool taint_do_security_scan(
337337

338338
logger.status() << "The security scanner has finished successfully."
339339
<< messaget::eom;
340-
tmprof_dump_as_json(
340+
TMPROF_DUMP(
341341
boost::filesystem::path(config.get_output_root_directory()) /
342342
"TMPROF.json");
343343
return true;

src/util/tmprof.cpp

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,56 @@ void enable_time_profiling(const bool state)
2323
std::list<tmprof_detail_datat> tmprof_detail_datat::records;
2424

2525
tmprof_detail_datat *
26-
tmprof_detail_datat::create(const char *name, const unsigned long line)
26+
tmprof_detail_datat::create(
27+
const char *name, const unsigned long line, const char *file)
2728
{
28-
records.emplace_back(name, line);
29+
records.emplace_back(name, line, file);
2930
return &records.back();
3031
}
3132

32-
void tmprof_detail_datat::on_hit(const double duration)
33+
void tmprof_detail_datat::on_run_begin()
3334
{
34-
total_time += duration;
35-
if(max_time < duration)
36-
max_time = duration;
37-
++hit_count;
35+
++num_runs;
36+
if(num_runs == 1U)
37+
start_time = std::chrono::high_resolution_clock::now();
3838
}
3939

40-
json_objectt tmprof_detail_datat::dump_as_json()
40+
void tmprof_detail_datat::on_run_end()
4141
{
42-
json_objectt root;
42+
if(num_runs == 1U)
43+
{
44+
auto const duration =
45+
std::chrono::duration<double>(
46+
std::chrono::high_resolution_clock::now() - start_time)
47+
.count();
48+
total_time += duration;
49+
if(max_time < duration)
50+
max_time = duration;
51+
++hit_count;
52+
}
53+
++run_count;
54+
max_num_runs = std::max(max_num_runs, num_runs);
55+
--num_runs;
56+
}
57+
58+
json_arrayt tmprof_detail_datat::dump_as_json()
59+
{
60+
json_arrayt root;
4361
for(const auto &record : records)
4462
if(record.get_hit_count() != 0ULL)
4563
{
4664
json_objectt table;
65+
table["file"] = json_stringt(record.get_file());
66+
table["line"] = json_numbert(std::to_string(record.get_line()));
67+
table["function"] = json_stringt(record.get_name());
4768
table["total_time"] =
4869
json_numbert(std::to_string(record.get_total_time()));
4970
table["max_time"] = json_numbert(std::to_string(record.get_max_time()));
5071
table["hit_count"] = json_numbert(std::to_string(record.get_hit_count()));
51-
std::stringstream sstr;
52-
sstr << record.get_name() << " [" << record.get_line() << "]";
53-
root[sstr.str()] = table;
72+
table["run_count"] = json_numbert(std::to_string(record.get_run_count()));
73+
table["max_runs"] =
74+
json_numbert(std::to_string(record.get_max_num_runs()));
75+
root.push_back(table);
5476
}
5577
return root;
5678
}

0 commit comments

Comments
 (0)