Skip to content

Commit

Permalink
Add tests and charts in scat for couples
Browse files Browse the repository at this point in the history
  • Loading branch information
Frky committed Jun 5, 2017
1 parent 403dcca commit b177788
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 38 deletions.
18 changes: 14 additions & 4 deletions src/pintool/couple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ VOID Commence() {
if (ifile.is_open()) {
/* Ignore first line (elapsed time) */
read_line(ifile);
/* Ignore second line (params of inference) */
read_line(ifile);
while (ifile) {
/* Read the prototype of one function */
fn_type_t *fn = read_one_type(ifile);
Expand Down Expand Up @@ -236,6 +238,8 @@ VOID Fini(INT32 code, VOID *v) {
/* Open output log file (result of this inference */
ofile.open(KnobOutputFile.Value().c_str());

ofile << "MAX_VALS=" << MAX_VALS << endl;

/* First we log the table fid <-> name */
log_ftable(ofile);

Expand Down Expand Up @@ -297,16 +301,19 @@ VOID Instruction(INS ins, VOID *v) {
}
}

if (INS_IsIndirectBranchOrCall(ins)) {
if (! INS_IsCall(ins)) {
INS_InsertCall(ins,
if (INS_IsIndirectBranchOrCall(ins) && !INS_IsFarCall(ins) && !INS_IsFarJump(ins) && !INS_IsFarRet(ins)) {
if ((!INS_IsCall(ins)) && INS_IsBranchOrCall(ins)
/* This condition fixes runtime crash of pin on some programs
(e.g. git) -- but I am not sure it is a correct answer, it
might have bad effects on the results of inference */
&& (INS_Category(ins) != XED_CATEGORY_COND_BR))
INS_InsertCall(ins,
IPOINT_BEFORE,
(AFUNPTR) fn_indirect_call,
IARG_CONST_CONTEXT,
IARG_BRANCH_TARGET_ADDR,
IARG_BOOL, true,
IARG_END);
}
}

if (INS_IsRet(ins)) {
Expand All @@ -329,6 +336,9 @@ int main(int argc, char * argv[])

if (PIN_Init(argc, argv)) return 1;

/* Get parameters of analysis from command line */
MAX_VALS = std::atoi(KnobMaxVals.Value().c_str());

/* Init function data structure */
fn_data = (fn_data_t **) calloc(NB_FN_MAX, sizeof(fn_data_t*));

Expand Down
3 changes: 3 additions & 0 deletions src/shell/chart/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class Chart(object):
"fn": "#bdc3c7",
"fp": "#7f8c8d",
"tot": "#c0392b",
"couples": "#2c3e50",
"left": "#7f8c8d",
"right": "#bdc3c7",
}

def __init__(self, logfile):
Expand Down
179 changes: 179 additions & 0 deletions src/shell/chart/couple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#-*- coding: utf-8 -*-

import os
import sys
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import pylab as P
import pandas as pd

from .chart import Chart
from .entry.couple import CoupleEntry

class CoupleChart(Chart):

def __init__(self, *args, **kwargs):
super(CoupleChart, self).__init__(*args, **kwargs)
self._analysis = "couple"
self.__parse_log()
self._data = sum(self._data.values(), list())

def __parse_log(self):
if not os.path.exists(self._log):
return
with open(self._log, "r") as f:
for line in f.readlines():
pgm = line.split(":")[0]
self._data.setdefault(pgm, list())
entry = CoupleEntry(line)
self._data[pgm].append(entry)

def get(self, param, defaults):
self._data.sort(key=lambda a: a.get(param))
data = dict()
val = -1
tot = 0
f, g, n = 0, 0, 0
for e in self._data:
skip = False
for k, v in defaults.items():
if k != param and e.get(k) != v:
print k, e.get(k), v
skip = True
break
if skip:
continue
if e.get(param) != val:
data[val] = (tot, f, g, n)
val = e.get(param)
tot = 0
f = 0
g = 0
n = 0
tot += e.tot
f += e.f
g += e.g
n += e.n
data[val] = (tot, f, g, n)
return data

def draw(self, data, name):
plt.figure(figsize=(12, 9))
ax = plt.subplot(111)
ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_visible(False)
plt.plot([0, max(data.keys())*1.05], [1, 1], "-", lw=0.5, color="black")
plt.plot([0, max(data.keys())*1.05], [0, 0], "-", lw=0.5, color="black")
# Ensure that the axis ticks only show up on the bottom and left of the plot.
# Ticks on the right and top of the plot are generally unnecessary chartjunk.
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()

# Limit the range of the plot to only where the data is.
# Avoid unnecessary whitespace.
plt.ylim(-0.1, 1.1)
plt.xlim(0, max(data.keys()) * 1.05)

plt.tick_params(axis="both", which="both", bottom="off", top="off",
labelbottom="on", left="off", right="off", labelleft="on")
tot = [v[0] for v in data.values()]
norm = colors.Normalize(0, max(tot))
tot = map(lambda a: norm(a), tot)
f = [v[1] for v in data.values()]
norm = colors.Normalize(0, max(f))
f = map(lambda a: norm(a), f)
g = [v[2] for v in data.values()]
norm = colors.Normalize(0, max(g))
g = map(lambda a: norm(a), g)
n = [v[3] for v in data.values()]
norm = colors.Normalize(0, max(n))
n = map(lambda a: norm(a), n)

# plt.plot(data.keys(), tot, 'o', lw=1, color=Chart.colors["tot"], label="functions analyzed (normalized)")
plt.plot(data.keys(), n, 'o', lw=1, color=Chart.colors["couples"], label="number of couples (normalized)")
plt.plot(data.keys(), f, 'o', lw=1, color=Chart.colors["left"], label="number of left operand (normalized)")
plt.plot(data.keys(), g, 'o', lw=1, color=Chart.colors["right"], label="right operand (normalized)")

plt.legend()

plt.savefig("test/chart/{}_{}.png".format(self._analysis, name), bbox_inches="tight")

def draw_accuracy(self, data, name):
tab = dict()
tab["tot"] = dict()
tab["f"] = dict()
tab["g"] = dict()
tab["n"] = dict()
order = ["tot", "n", "f", "g"]
for c, e in enumerate(data):
for k in tab.keys():
tab[k].setdefault(e.pgm, e.get(k))
for k in order:
sys.stdout.write("& {} ".format(k))
sys.stdout.write("\\\\\n")
for p in tab["tot"].keys():
sys.stdout.write("{} ".format(p))
for k in order:
if not isinstance(tab[k][p], float):
sys.stdout.write("& {} ".format(tab[k][p]))
else:
sys.stdout.write("& {0:.2f} ".format(tab[k][p]))
sys.stdout.write("\\\\\n")
sys.stdout.write("TOTAL ")
for k in order:
if k == "acc_in":
total = map(lambda a: a[0] * a[1], zip(tab[k].values(), tab["tot_in"].values()))
total = sum(total)/float(sum(tab["tot_in"].values()))
elif k == "acc_out":
total = map(lambda a: a[0] * a[1], zip(tab[k].values(), tab["tot_out"].values()))
total = sum(total)/float(sum(tab["tot_out"].values()))
else:
total = sum(tab[k].values())
if isinstance(total, int):
sys.stdout.write("& {} ".format(total))
else:
sys.stdout.write("& {0:.2f}".format(total))
sys.stdout.write("\\\\\n")
return

def draw_var(self, data, name):
plt.figure(figsize=(12, 9))
ax = plt.subplot(111)
bar_width = 0.5
bar_l = [i + 1 for i in range(len(data))]
tick_pos = [ i + (bar_width/2) for i in bar_l ]

couples = map(lambda a: a.n, data)
f = map(lambda a: a.f, data)
g = map(lambda a: a.g, data)

ax.bar(bar_l, couples, width=bar_width, label="number of couples",
alpha=1, color=Chart.colors["couples"])
ax.bar(bar_l, f, width=bar_width, label="number of left operands",
alpha=1, bottom=couples, color=Chart.colors["left"])
ax.bar(bar_l, g, width=bar_width, label="number of right operands",
alpha=1, bottom=map(lambda a: a[0] + a[1], zip(couples, f)), color=Chart.colors["right"])

# Limit the range of the plot to only where the data is.
# Avoid unnecessary whitespace.
# plt.ylim(0.9, 1.01)
plt.xlim(0, len(data) * 1.05)

ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_visible(False)

# Ensure that the axis ticks only show up on the bottom and left of the plot.
# Ticks on the right and top of the plot are generally unnecessary chartjunk.
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()

# plt.xticks(tick_pos, map(lambda a: a.tot_in + a.tot_out, data), rotation="vertical")
plt.tick_params(axis="both", which="both", bottom="off", top="off",
labelbottom="off", left="off", right="off", labelleft="on")
plt.legend()

plt.savefig("test/chart/{}_{}.png".format(self._analysis, name), bbox_inches="tight")
66 changes: 66 additions & 0 deletions src/shell/chart/entry/couple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#-*- coding: utf-8 -*-

from .entry import Entry

class CoupleEntry(Entry):

def __init__(self, line, *args, **kwargs):
l = line[:-1].split(":")
self._pgm = l[0]
self._minvals = int(l[1])
self._maxvals = int(l[2])
self._rho = float(l[3])
self._tot = int(l[4])
self._f, self._g, self._n = map(int, l[5:])
super(CoupleEntry, self).__init__(*args, **kwargs)

def merge(self, e):
self._f += e.f
self._g += e.g
self._n += e.n
self._tot += e.tot
return self

@property
def min_vals(self):
return int(self._minvals)

@property
def max_vals(self):
return int(self._maxvals)

@property
def rho(self):
return float(self._rho)

@property
def f(self):
return self._f

@property
def g(self):
return self._g

@property
def n(self):
return self._n

@property
def tot(self):
return self._tot

def get(self, param):
if param == "min_vals":
return self.min_vals
if param == "max_vals":
return self.max_vals
elif param == "rho":
return self.rho
elif param == "f":
return self.f
elif param == "g":
return self.g
elif param == "n":
return self.n
elif param == "tot":
return self.tot
53 changes: 36 additions & 17 deletions src/shell/command/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from src.shell.chart.arity import ArityChart
from src.shell.chart.type import TypeChart
from src.shell.chart.couple import CoupleChart

class ChartCmd(ICommand):
"""
Expand All @@ -30,6 +31,8 @@ def __init__(self, resdir, conf, *args, **kwargs):
def __get_res(self, inf="", param="", pgm=""):
if param == "accuracy":
return "{}/{}_{}.res".format(self.__resdir, param, inf)
elif inf == "couple":
return "{}/{}_{}.res".format(self.__resdir, inf, "general")
else:
return "{}/{}_{}.res".format(self.__resdir, pgm, inf)

Expand All @@ -40,21 +43,37 @@ def run(self, s, *args, **kwargs):
pgm = split[2]
else:
pgm = "test"
if param != "accuracy":
defaults = dict()
for k, v in self.__conf[inf][param].items():
if k not in ["min", "max", "step"]:
defaults[k] = v
inp = param in ["min_calls", "param_threshold", "min_vals", "max_vals", "addr_threshold"]
outp = param in ["min_calls", "ret_threshold", "min_vals", "max_vals", "addr_threshold"]
if inf == "arity":
chart = ArityChart(self.__get_res(inf, param, pgm))
else:
chart = TypeChart(self.__get_res(inf, param, pgm))
if param == "accuracy":
chart.draw_accuracy(chart.get_accuracy(), "accuracy")
elif param == "variability":
chart.draw_var(chart.get_var(pgm, defaults), "{}_var".format(pgm))
else:
chart.draw(chart.get(param, defaults, inp=inp, outp=outp), pgm + "_" + param)
if inf == "arity" or inf == "type":
if param != "accuracy":
defaults = dict()
for k, v in self.__conf[inf][param].items():
if k not in ["min", "max", "step"]:
defaults[k] = v
inp = param in ["min_calls", "param_threshold", "min_vals", "max_vals", "addr_threshold"]
outp = param in ["min_calls", "ret_threshold", "min_vals", "max_vals", "addr_threshold"]
if inf == "arity":
chart = ArityChart(self.__get_res(inf, param, pgm))
else:
chart = TypeChart(self.__get_res(inf, param, pgm))
if param == "accuracy":
chart.draw_accuracy(chart.get_accuracy(), "accuracy")
elif param == "variability":
chart.draw_var(chart.get_var(pgm, defaults), "{}_var".format(pgm))
else:
chart.draw(chart.get(param, defaults, inp=inp, outp=outp), pgm + "_" + param)
elif inf == "couple":
if param == "general":
chart = CoupleChart(self.__get_res(inf, param, pgm))
chart.draw_accuracy(chart.get_accuracy(), "general")
else:
defaults = dict()
for k, v in self.__conf[inf][param].items():
if k not in ["min", "max", "step"]:
defaults[k] = v
if param == "variability":
chart = CoupleChart(self.__get_res(inf, param, pgm))
chart.draw_var(chart.get_var(pgm, defaults), "var")
else:
chart = CoupleChart("{}/{}".format(self.__resdir, param))
chart.draw(chart.get(param, defaults), param)

2 changes: 1 addition & 1 deletion src/shell/command/couple.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ def run(self, s, *args, **kwargs):
except IOError:
self.stderr("Logs for binary \"{}\" not found".format(s[0]))
return
Couple(logfile, s[0], self.stdout).run()
Couple(logfile, s[0]).run()
Loading

0 comments on commit b177788

Please sign in to comment.