From 203a374b54c202d6025828d57d47ad63f571c92f Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 4 Aug 2014 02:59:02 +0400 Subject: [PATCH] Do not use argparge for parsing --env and --cwd It took 2/3 of do_render call according to profiler. New variant takes only 1/6. WARNING: This commit will break all powerline installations with running daemon because it changes communication protocol. You must kill and restart all your powerline daemons for powerline to function properly. Highlight @kovidgoyal --- client/powerline.c | 17 ++++++++++------- client/powerline.py | 11 ++++++----- client/powerline.sh | 5 +++-- scripts/powerline-daemon | 20 ++++++++++++-------- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/client/powerline.c b/client/powerline.c index de14ac26..fd08c066 100644 --- a/client/powerline.c +++ b/client/powerline.c @@ -60,6 +60,7 @@ int main(int argc, char *argv[]) { struct sockaddr_un server; char address[ADDRESS_SIZE]; const char eof[2] = "\0\0"; + char num_args[NUM_ARGS_SIZE]; char buf[BUF_SIZE]; char *newargv[NEW_ARGV_SIZE]; char *wd = NULL; @@ -90,24 +91,26 @@ int main(int argc, char *argv[]) { execvp("powerline-render", newargv); } + snprintf(num_args, NUM_ARGS_SIZE, "%x", argc - 1); + do_write(sd, num_args, strlen(num_args)); + do_write(sd, eof, 1); + for (i = 1; i < argc; i++) { do_write(sd, argv[i], strlen(argv[i])); do_write(sd, eof, 1); } - for(envp=environ; *envp; envp++) { - do_write(sd, "--env=", 6); - do_write(sd, *envp, strlen(*envp)); - do_write(sd, eof, 1); - } - wd = getcwd(NULL, 0); if (wd != NULL) { - do_write(sd, "--cwd=", 6); do_write(sd, wd, strlen(wd)); free(wd); wd = NULL; } + for(envp=environ; *envp; envp++) { + do_write(sd, *envp, strlen(*envp)); + do_write(sd, eof, 1); + } + do_write(sd, eof, 2); i = -1; diff --git a/client/powerline.py b/client/powerline.py index 89e56f8e..5cec13e8 100755 --- a/client/powerline.py +++ b/client/powerline.py @@ -42,7 +42,8 @@ fenc = sys.getfilesystemencoding() or 'utf-8' if fenc == 'ascii': fenc = 'utf-8' -args = [x.encode(fenc) if isinstance(x, type('')) else x for x in sys.argv[1:]] +args = [bytes('%x' % (len(sys.argv) - 1))] +args.extend((x.encode(fenc) if isinstance(x, type('')) else x for x in sys.argv[1:])) try: cwd = os.getcwd() @@ -51,17 +52,17 @@ except EnvironmentError: else: if isinstance(cwd, type('')): cwd = cwd.encode(fenc) - args.append(b'--cwd=' + cwd) + args.append(cwd) env = (k + b'=' + v for k, v in os.environ.items()) env = (x if isinstance(x, bytes) else x.encode(fenc, 'replace') for x in env) -args.extend((b'--env=' + x for x in env)) +args.extend(env) EOF = b'\0\0' for a in args: - eintr_retry_call(sock.sendall, a + EOF[0]) + eintr_retry_call(sock.sendall, a + b'\0') eintr_retry_call(sock.sendall, EOF) @@ -74,4 +75,4 @@ while True: sock.close() -print (b''.join(received)) +sys.stdout.write(b''.join(received)) diff --git a/client/powerline.sh b/client/powerline.sh index a56bc296..5860b7f8 100755 --- a/client/powerline.sh +++ b/client/powerline.sh @@ -5,11 +5,12 @@ ADDRESS="powerline-ipc-${UID:-`id -u`}" # Warning: env -0 does not work in busybox. Consider switching to parsing # `set` output in this case ( + printf '%x\0' "$#" for argv in "$@" ; do printf '%s\0' "$argv" done - env -0 | sed 's/\(\x00\)\([^\x00]\)\|^/\1--env=\2/g' - printf -- '--cwd=%s\0' "$PWD" + printf '%s\0' "$PWD" + env -0 ) | socat -lf/dev/null -t 10 - abstract-client:"$ADDRESS" if test $? -ne 0 ; then diff --git a/scripts/powerline-daemon b/scripts/powerline-daemon index 92915a3d..20794575 100755 --- a/scripts/powerline-daemon +++ b/scripts/powerline-daemon @@ -48,8 +48,6 @@ class NonInteractiveArgParser(ArgumentParser): parser = get_argparser(parser=NonInteractiveArgParser, description='powerline daemon') -parser.add_argument('--cwd', metavar='PATH') -parser.add_argument('--env', action='append') EOF = b'EOF\0\0' @@ -67,11 +65,10 @@ class PowerlineDaemon(ShellPowerline): return super(PowerlineDaemon, self).get_log_handler() -def render(args): +def render(args, environ, cwd): global logger global config_loader - environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args.env))) - cwd = environ.get('PWD', args.cwd or '/') + cwd = cwd or environ.get('PWD', '/') segment_info = { 'getcwd': lambda: cwd, 'home': environ.get('HOME', home), @@ -175,11 +172,18 @@ def safe_bytes(o, encoding=encoding): return safe_bytes(str(e), encoding) +def parse_args(req): + args = [x.decode(encoding) for x in req.split(b'\0') if x] + numargs = int(args[0], 16) + shell_args = parser.parse_args(args[1:numargs + 1]) + cwd = args[numargs + 1] + environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args[numargs + 2:]))) + return shell_args, environ, cwd + + def do_render(req): try: - args = [x.decode(encoding) for x in req.split(b'\0') if x] - args = parser.parse_args(args) - return safe_bytes(render(args)) + return safe_bytes(render(*parse_args(req))) except Exception as e: return safe_bytes(str(e))