Permalink
Browse files

Merge pull request #2 from liblarch/performance

Great performance optimization from Izidor
  • Loading branch information...
2 parents 66e5651 + 22ba3fc commit 887b0ad385262484b161697e1afc59bf7d797209 @ploum ploum committed May 4, 2012
Showing with 46 additions and 70 deletions.
  1. +1 −1 liblarch/__init__.py
  2. +8 −11 liblarch/filteredtree.py
  3. +28 −32 liblarch/processqueue.py
  4. +5 −22 liblarch/tree.py
  5. +2 −2 liblarch/treenode.py
  6. +2 −2 tests/test_liblarch.py
@@ -30,7 +30,7 @@
#
#The minor number is incremented when a method is added to the API
#The major number is incremented if an existing method is removed or modified
-api="1.0"
+api="1.1"
def is_compatible(request):
major,minor=request.split(".")
@@ -1,4 +1,3 @@
-from __future__ import with_statement
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Liblarch - a library to handle directed acyclic graphs
@@ -19,7 +18,6 @@
# -----------------------------------------------------------------------------
import gobject
-import processqueue
class FilteredTree():
""" FilteredTree is the most important and also the most buggy part of
@@ -60,7 +58,6 @@ def __init__(self, tree, filtersbank, name=None, refresh=True):
self.nodes[self.root_id] = {'parents': [], 'children': []}
self.cache_paths = {}
- #FIXME fix all side cases
self.filter_cache = {}
# Connect to signals from MainTree
@@ -110,6 +107,7 @@ def callback(self, event, node_id, path, neworder=None):
The runonce event is actually only run once, when a given task appears.
"""
+
if event == 'added':
for func,nid,param in self.cllbcks.get(node_id,[]):
@@ -131,13 +129,13 @@ def callback(self, event, node_id, path, neworder=None):
def __external_modify(self, node_id):
return self.__update_node(node_id,direction="both")
- def __update_node(self, node_id,direction):
+ def __update_node(self, node_id, direction):
'''update the node node_id and propagate the
change in direction (up|down|both) '''
+
if node_id == self.root_id:
return None
-
- #Updating the node itself.
+
current_display = self.is_displayed(node_id)
new_display, intransparent_display = self.__is_displayed_by_transparency(node_id)
@@ -155,8 +153,6 @@ def __update_node(self, node_id,direction):
if node_id in self.filter_cache[fcname]['nodes']:
self.filter_cache[fcname]['nodes'].remove(node_id)
self.filter_cache[fcname]['count'] = len(self.filter_cache[fcname]['nodes'])
-
-
completely_updated = True
@@ -320,6 +316,7 @@ def test_validity(self):
#### OTHER ####################################################################
def refilter(self):
# Find out it there is at least one flat filter
+ self.filter_cache = {}
self.__flat = False
for filter_name in self.applied_filters:
filt = self.fbank.get_filter(filter_name)
@@ -339,7 +336,7 @@ def refilter(self):
while queue != []:
node_id = queue.pop(0)
- #FIXME: decide which is the best direction
+ # FIXME: decide which is the best direction
self.__update_node(node_id, direction="both")
node = self.tree.get_node(node_id)
@@ -592,11 +589,11 @@ def get_n_nodes(self, withfilters=[], include_transparent=True):
displayed = filt.is_displayed(node_id)
if not displayed:
break
- if build_cache:
- self.filter_cache[ffname]['nodes'].add(node_id)
if displayed:
total_count += 1
+ if build_cache:
+ self.filter_cache[ffname]['nodes'].add(node_id)
if build_cache:
self.filter_cache[ffname]['count'] = total_count
@@ -32,6 +32,7 @@ def __init__(self):
self._vip_queue = []
self._handler = None
self._lock = threading.Lock()
+ self._origin_thread = threading.current_thread()
self.count = 0
@@ -43,46 +44,41 @@ def process_queue(self):
# return True to process other requests as well
return True
- def low_push(self, *element):
+ def push(self, *element, **kwargs):
""" Add a new element to the queue.
- Schedule its processing if it is not already.
- vip element are in a priority queue. They will be processed first
- (this comment was actually written in Berlin Airport, after having
- to wait in an economy class queue)"""
- self._lock.acquire()
- self._low_queue.append(element)
-
- if self._handler is None:
- self._handler = gobject.idle_add(self.process_queue)
- self._lock.release()
+ Process actions from the same thread as the thread which created
+ this queue immediately. What does it mean? When I use liblarch
+ without threads, all actions are processed immediately. In GTG,
+ this queue is created by the main thread which process GUI. When
+ GUI callback is triggered, process those actions immediately because
+ no protection is needed. However, requests from synchronization
+ services are put in the queue.
- def push(self, *element):
- """ Add a new element to the queue.
-
- Schedule its processing if it is not already.
+ Application can choose which kind of priority should have an update.
+ If the request is not in the queue of selected priority, add it and
+ setup callback.
"""
- self._lock.acquire()
- lon = len(self._queue)
- if element not in self._queue:
- self._queue.append(element)
- if self._handler is None:
- self._handler = gobject.idle_add(self.process_queue)
- self._lock.release()
-
- def priority_push(self, *element):
- """ Add a new element to the queue.
+ if self._origin_thread == threading.current_thread():
+ func = element[0]
+ func(*element[1:])
+ return
+
+ priority = kwargs.get('priority')
+ if priority == 'low':
+ queue = self._low_queue
+ elif priority == 'high':
+ queue = self._vip_queue
+ else:
+ queue = self._queue
- Schedule its processing if it is not already.
- vip element are in a priority queue. They will be processed first
- (this comment was actually written in Berlin Airport, after having
- to wait in an economy class queue)"""
self._lock.acquire()
- self._vip_queue.append(element)
+ if element not in queue:
+ queue.append(element)
+ if self._handler is None:
+ self._handler = gobject.idle_add(self.process_queue)
- if self._handler is None:
- self._handler = gobject.idle_add(self.process_queue)
self._lock.release()
def process(self):
View
@@ -17,7 +17,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# -----------------------------------------------------------------------------
-import threading
import processqueue
from liblarch.treenode import _Node
@@ -40,7 +39,6 @@ def __init__(self):
_Node._set_tree(self.root,self)
self._queue = processqueue.SyncQueue()
- self._origin_thread = threading.current_thread()
def __str__(self):
return "<Tree: root = '%s'>" % self.root
@@ -81,34 +79,19 @@ def _callback(self, event, node_id):
####### INTERFACE FOR HANDLING REQUESTS #######################################
def add_node(self, node, parent_id=None, priority="low"):
- self._external_request(self._add_node, priority, node, parent_id)
+ self._queue.push(self._add_node, node, parent_id, priority=priority)
def remove_node(self, node_id, recursive=False):
- self._external_request(self._remove_node, True, node_id, recursive)
+ self._queue.push(self._remove_node, node_id, recursive)
def modify_node(self, node_id, priority="low"):
- self._external_request(self._modify_node, priority, node_id)
+ self._queue.push(self._modify_node, node_id, priority=priority)
def new_relationship(self, parent_id, child_id):
- self._external_request(self._new_relationship, False, parent_id, child_id)
+ self._queue.push(self._new_relationship, parent_id, child_id)
def break_relationship(self, parent_id, child_id):
- self._external_request(self._break_relationship, False, parent_id, child_id)
-
- def _external_request(self, request_type, priority, *args):
- """ Put the reqest into queue and in the main thread handle it """
- #FIXME better document this function
- #I'm really wondering what is this line about
- #It doesn't seem right nor useful, except for unit tests.
- if self._origin_thread == threading.current_thread():
- request_type(*args)
- else:
- if priority == "high":
- self._queue.priority_push(request_type, *args)
- elif priority == "normal" or priority == "medium":
- self._queue.push(request_type, *args)
- else:
- self._queue.low_push(request_type, *args)
+ self._queue.push(self._break_relationship, parent_id, child_id)
def refresh_all(self):
""" Refresh all nodes """
@@ -45,10 +45,10 @@ def get_id(self):
""" Return node_id """
return self.node_id
- def modified(self,priority="low"):
+ def modified(self, priority="low"):
""" Force to update node (because it has changed) """
if self.tree:
- self.tree.modify_node(self.node_id,priority=priority)
+ self.tree.modify_node(self.node_id, priority=priority)
def _set_tree(self, tree):
""" Set tree which is should contain this node.
@@ -733,9 +733,9 @@ def test_cyclic_paradox(self):
self.assertTrue('1' in self.mainview.node_parents('0'))
self.assertTrue('0' in self.mainview.node_parents('temp'))
#direct circular relationship
- self.assertRaises(Exception,self.tree.add_parent,'0','temp')
+ self.assertRaises(Exception, self.tree.add_parent, '0', 'temp')
#More complex circular relationship
- self.assertRaises(Exception,self.tree.add_parent,'1','temp')
+ self.assertRaises(Exception, self.tree.add_parent, '1', 'temp')
# And then printing => if it stops, nothing ciruclar stays there
view.print_tree(True)

0 comments on commit 887b0ad

Please sign in to comment.