Merge lp:~ensoft-opensource/ensoft-sextant/perf into lp:ensoft-sextant

Proposed by Patrick Stevens
Status: Merged
Approved by: Phil Connell
Approved revision: 19
Merged at revision: 21
Proposed branch: lp:~ensoft-opensource/ensoft-sextant/perf
Merge into: lp:ensoft-sextant
Diff against target: 118 lines (+52/-21)
1 file modified
src/sextant/db_api.py (+52/-21)
To merge this branch: bzr merge lp:~ensoft-opensource/ensoft-sextant/perf
Reviewer Review Type Date Requested Status
Phil Connell Approve
Review via email: mp+233077@code.launchpad.net

Commit message

Speed up program upload by batching queries differently

Upload now happens in two passes:
 - Function nodes are added.
 - Links between nodes are added.

Description of the change

Speedup in program upload (vim uploads three times faster). This is achieved by executing the relevant blueprint.

To post a comment you must log in.
18. By Patrick Stevens <email address hidden>

Remove old code

19. By Patrick Stevens <email address hidden>

Add a comment

Revision history for this message
Phil Connell (pconnell) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/sextant/db_api.py'
--- src/sextant/db_api.py 2014-08-27 09:07:39 +0000
+++ src/sextant/db_api.py 2014-09-03 14:12:18 +0000
@@ -67,7 +67,8 @@
67 self.program_name = program_name67 self.program_name = program_name
68 self.parent_database_connection = sextant_connection68 self.parent_database_connection = sextant_connection
69 self._functions = {}69 self._functions = {}
70 self._new_tx = None70 self._funcs_tx = None # transaction for uploading functions
71 self._calls_tx = None # transaction for uploading relationships
7172
72 if self.parent_database_connection:73 if self.parent_database_connection:
73 # we'll locally use db for short74 # we'll locally use db for short
@@ -80,10 +81,37 @@
80 date=date)81 date=date)
81 self._parent_id = parent_function.id82 self._parent_id = parent_function.id
8283
83 self._new_tx = db.transaction(using_globals=False, for_query=True)84 self._funcs_tx = db.transaction(using_globals=False, for_query=True)
85 self._calls_tx = db.transaction(using_globals=False, for_query=True)
8486
85 self._connections = []87 self._connections = []
8688
89 @staticmethod
90 def _get_display_name(function_name):
91 """
92 Gets the name we will display to the user for this function name.
93
94 For instance, if function_name were __libc_start_main@plt, we would
95 return ("__libc_start_main", "plt_stub"). The returned function type is
96 currently one of "plt_stub", "function_pointer" or "normal".
97
98 :param function_name: the name straight from objdump of a function
99 :return: ("display name", "function type")
100
101 """
102
103 if function_name[-4:] == "@plt":
104 display_name = function_name[:-4]
105 function_group = "plt_stub"
106 elif function_name[:20] == "_._function_pointer_":
107 display_name = function_name
108 function_group = "function_pointer"
109 else:
110 display_name = function_name
111 function_group = "normal"
112
113 return display_name, function_group
114
87 def add_function(self, function_name):115 def add_function(self, function_name):
88 """116 """
89 Adds a function to the program, ready to be sent to the remote database.117 Adds a function to the program, ready to be sent to the remote database.
@@ -98,21 +126,14 @@
98 if self.class_contains_function(function_name):126 if self.class_contains_function(function_name):
99 return True127 return True
100128
101 if function_name[-4:] == "@plt":129 display_name, function_group = self._get_display_name(function_name)
102 display_name = function_name[:-4]
103 function_group = "plt_stub"
104 elif function_name[:20] == "_._function_pointer_":
105 display_name = function_name
106 function_group = "function_pointer"
107 else:
108 display_name = function_name
109 function_group = "normal"
110130
111 query = ('START n = node({}) '131 query = ('START n = node({}) '
112 'CREATE (n)-[:subject]->(m:func {{type: "{}", name: "{}"}})')132 'CREATE (n)-[:subject]->(m:func {{type: "{}", name: "{}"}}) '
133 'RETURN m.name, id(m)')
113 query = query.format(self._parent_id, function_group, display_name)134 query = query.format(self._parent_id, function_group, display_name)
114135
115 self._new_tx.append(query)136 self._funcs_tx.append(query)
116137
117 self._functions[function_name] = function_name138 self._functions[function_name] = function_name
118139
@@ -159,13 +180,6 @@
159 self.add_function(fn_calling)180 self.add_function(fn_calling)
160181
161 if not self.class_contains_call(fn_calling, fn_called):182 if not self.class_contains_call(fn_calling, fn_called):
162 query = ('START p = node({}) '
163 'MATCH (p)-[:subject]->(n) WHERE n.name = "{}" '
164 'MATCH (p)-[:subject]->(m) WHERE m.name = "{}" '
165 'CREATE (n)-[:calls]->(m)')
166 query = query.format(self._parent_id, fn_calling, fn_called)
167 self._new_tx.append(query)
168
169 self._connections.append((fn_calling, fn_called))183 self._connections.append((fn_calling, fn_called))
170184
171 return True185 return True
@@ -175,7 +189,24 @@
175 Call this when you are finished with the object.189 Call this when you are finished with the object.
176 Changes are not synced to the remote database until this is called.190 Changes are not synced to the remote database until this is called.
177 """191 """
178 self._new_tx.commit()192 functions = self._funcs_tx.commit() # send off the function names
193
194 # now functions is a list of QuerySequence objects, which each have a
195 # .elements property which produces [['name', id]]
196
197 id_funcs = dict([seq.elements[0] for seq in functions])
198 logging.info('Functions uploaded. Uploading calls...')
199
200 # so id_funcs is a dict with id_funcs['name'] == id
201 for call in self._connections:
202 query = ('MATCH n WHERE id(n) = {} '
203 'MATCH m WHERE id(m) = {} '
204 'CREATE (n)-[:calls]->(m)')
205 query = query.format(id_funcs[self._get_display_name(call[0])[0]],
206 id_funcs[self._get_display_name(call[1])[0]])
207 self._calls_tx.append(query)
208
209 self._calls_tx.commit()
179210
180211
181class FunctionQueryResult:212class FunctionQueryResult:

Subscribers

People subscribed via source and target branches