{"action":"created","issue":{"url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/103","labels_url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/103/labels{/name}","comments_url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/103/comments","events_url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/103/events","html_url":"https://github.com/dictation-toolbox/aenea/issues/103","id":112040382,"number":103,"title":"Long action chains take a significant amount of time to execute","user":{"login":"mzizzi","id":6410431,"avatar_url":"https://avatars.githubusercontent.com/u/6410431?v=3","gravatar_id":"","url":"https://api.github.com/users/mzizzi","html_url":"https://github.com/mzizzi","followers_url":"https://api.github.com/users/mzizzi/followers","following_url":"https://api.github.com/users/mzizzi/following{/other_user}","gists_url":"https://api.github.com/users/mzizzi/gists{/gist_id}","starred_url":"https://api.github.com/users/mzizzi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzizzi/subscriptions","organizations_url":"https://api.github.com/users/mzizzi/orgs","repos_url":"https://api.github.com/users/mzizzi/repos","events_url":"https://api.github.com/users/mzizzi/events{/privacy}","received_events_url":"https://api.github.com/users/mzizzi/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":17,"created_at":"2015-10-18T20:47:43Z","updated_at":"2015-11-13T03:09:40Z","closed_at":null,"body":"After playing with aenea for some time I started digging into trying to tighten the latency between \"say something\" and \"do something\".  \r\n\r\nOccasionally I noticed a delay AFTER recognition when a long chain of commands was to be executed so I came up with this test\r\n\r\n```python\r\nfrom aenea import Text\r\n\r\ndef time_actions(count=20, data=None):\r\n    s = time.time()\r\n    for _ in range(0, count):\r\n        Text('abc').execute(data=data)\r\n    return time.time() - s\r\n\r\n# >>> time_actions(count=20)\r\n# 0.43 seconds\r\n```\r\n\r\nThat means that aenea takes almost half a second to perform 20 actions client to server.  This is on the high end of what we might see with a long-ish dictation but not too uncommon.  Latency is high enough as it is.  We can definitely shave down ~0.4 seconds.\r\n\r\nI noticed I wasn't passing the optional `data` parameter to action.execute.  So I tried again.\r\n```python\r\n# >>> time_actions(count=20, data=ensure_execution_context({}))\r\n# 0.20 seconds\r\n```\r\n\r\nExplicitly passing execution context prevents aenea from having to query it between nearly ever action.  This saves the server from having to shell out repeatedly to get context.  \r\n\r\nI did one last test to see just how much making multiple rpc calls hurts on the longer chains\r\n```python\r\nclass BatchTextActionExecutor(object):\r\n    def __init__(self):\r\n        self.batch = []\r\n        self.original_write_text = None\r\n\r\n    def __enter__(self):\r\n        batch = self.batch\r\n\r\n        def write_text_patch(*args, **kwargs):\r\n            batch.append(('write_text', args, kwargs))\r\n\r\n        self.original_write_text = aenea.communications.server.write_text\r\n        aenea.communications.server.write_text = write_text_patch\r\n\r\n    def __exit__(self, exc_type, exc_val, exc_tb):\r\n        aenea.communications.server.multiple_actions(self.batch)\r\n        aenea.communications.server.write_text = self.original_write_text\r\n\r\ndef time_batch_actions(count=20, data=None):\r\n    s = time.time()\r\n    with BatchTextActionExecutor():\r\n        for _ in range(0, count):\r\n            Text('abc').execute(data=data)\r\n    return time.time() - s\r\n\r\n# time_batch_actions(count=20, data=ensure_execution_context())\r\n# 0.10 seconds \r\n```\r\n\r\nThe above context manager is a proof of concept.  It patches aenea's proxy to waits for multiple actions to be executed.  Upon leaving the context manager all commands are flushed to the aenea server in a single RPC.  By doing so the post recognition latency is reduced even further.  This could be improved further by not shelling out 20 times to xdotool on the server.\r\n\r\nI'd like to know if anyone else thinks batch action execution is something worth investing more time in.  I feel that recognition is slow enough as it is and that any reduction in latency is a win.\r\n\r\n**TL;DR** Post recognition latency between nearly 0.5 seconds on longish action chains.  We can optimize to ~0.1 seconds.  Is it worth the effort?\r\n\r\ngist containing some of the test hacks:\r\nhttps://gist.github.com/mzizzi/fd2924a8d68a33ef0ec2\r\n"},"comment":{"url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/comments/156310361","html_url":"https://github.com/dictation-toolbox/aenea/issues/103#issuecomment-156310361","issue_url":"https://api.github.com/repos/dictation-toolbox/aenea/issues/103","id":156310361,"user":{"login":"calmofthestorm","id":187310,"avatar_url":"https://avatars.githubusercontent.com/u/187310?v=3","gravatar_id":"","url":"https://api.github.com/users/calmofthestorm","html_url":"https://github.com/calmofthestorm","followers_url":"https://api.github.com/users/calmofthestorm/followers","following_url":"https://api.github.com/users/calmofthestorm/following{/other_user}","gists_url":"https://api.github.com/users/calmofthestorm/gists{/gist_id}","starred_url":"https://api.github.com/users/calmofthestorm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/calmofthestorm/subscriptions","organizations_url":"https://api.github.com/users/calmofthestorm/orgs","repos_url":"https://api.github.com/users/calmofthestorm/repos","events_url":"https://api.github.com/users/calmofthestorm/events{/privacy}","received_events_url":"https://api.github.com/users/calmofthestorm/received_events","type":"User","site_admin":false},"created_at":"2015-11-13T03:09:40Z","updated_at":"2015-11-13T03:09:40Z","body":"Also if I'm reading this correctly, we are currently discussing a polling approach using a library, rather than the event driven approach above. Is this correct? If the calls are as fast as the numbers above I see little reason to proceed with the complexity of an event driven implementation"}}