From 4afadab95824e12b551276d2fbf91199082d6df9 Mon Sep 17 00:00:00 2001
From: Jonas Haag <jonas@lophus.org>
Date: Mon, 13 Jun 2016 21:34:21 +0200
Subject: [PATCH 1/2] Prototype: use separate process for gzip

---
 src/vmprof_common.h | 48 +++++++++++++++++++++++++++++++++++++++++----
 src/vmprof_main.h   |  9 ++++++++-
 2 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/src/vmprof_common.h b/src/vmprof_common.h
index 38c3a6a3..c2d24149 100644
--- a/src/vmprof_common.h
+++ b/src/vmprof_common.h
@@ -11,6 +11,8 @@ static int opened_profile(char *interp_name, int memory);
 static struct profbuf_s *volatile current_codes;
 #endif
 
+#define ENABLE_GZIP (defined(__unix__) || defined(__APPLE__))
+
 #define MAX_STACK_DEPTH   \
     ((SINGLE_BUF_SIZE - sizeof(struct prof_stacktrace_s)) / sizeof(void *))
 
@@ -32,6 +34,34 @@ typedef struct prof_stacktrace_s {
     void *stack[];
 } prof_stacktrace_s;
 
+#if ENABLE_GZIP
+#include "tinygzip.c"
+static int pipe_gzip(int fd)
+{
+    int pipefds[2];
+
+    if (pipe(pipefds) == -1)
+        return -1;
+
+    pid_t pid = fork();
+    switch (pid) {
+    case -1:
+        close(pipefds[0]);
+        close(pipefds[1]);
+        return -1;
+    case 0:
+        close(pipefds[1]);
+        if (tinygz(pipefds[0], fd)) {
+            perror("gzip");
+            exit(1);
+        }
+        exit(0);
+    default:
+        close(pipefds[0]);
+        return pipefds[1];
+    }
+}
+#endif
 
 RPY_EXTERN
 char *vmprof_init(int fd, double interval, int memory, char *interp_name)
@@ -50,13 +80,23 @@ char *vmprof_init(int fd, double interval, int memory, char *interp_name)
     if (memory)
         return "memory tracking not supported on non-linux";
 #endif
+
     assert(fd >= 0);
+#if ENABLE_GZIP
+    int gzfd = pipe_gzip(fd);
+    if (gzfd < 0)
+        goto err;
+    profile_file = gzfd;
+#else
     profile_file = fd;
-    if (opened_profile(interp_name, memory) < 0) {
-        profile_file = -1;
-        return strerror(errno);
-    }
+#endif
+    if (opened_profile(interp_name, memory) < 0)
+        goto err;
     return NULL;
+
+err:
+    profile_file = -1;
+    return strerror(errno);
 }
 
 static int read_trace_from_cpy_frame(PyFrameObject *frame, void **result, int max_depth)
diff --git a/src/vmprof_main.h b/src/vmprof_main.h
index e0f0a69b..c6e13cab 100644
--- a/src/vmprof_main.h
+++ b/src/vmprof_main.h
@@ -345,8 +345,15 @@ static int close_profile(void)
 
     close(proc_file);
     proc_file = -1;
-    /* don't close() the file descriptor from here */
+
+#if ENABLE_GZIP
+    /* This doesn't close() the original file descriptor */
+    close(profile_file);
+#else
+    /* Don't close() the original file descriptor from here */
+#endif
     profile_file = -1;
+
     return 0;
 }
 

From acb9e521770f9dd4355bc3a23bbe8bfc079d7855 Mon Sep 17 00:00:00 2001
From: Jonas Haag <jonas@lophus.org>
Date: Mon, 13 Jun 2016 21:37:30 +0200
Subject: [PATCH 2/2] Forgot this file

---
 src/tinygzip.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 src/tinygzip.c

diff --git a/src/tinygzip.c b/src/tinygzip.c
new file mode 100644
index 00000000..0ff01597
--- /dev/null
+++ b/src/tinygzip.c
@@ -0,0 +1,61 @@
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <zlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define READ_BUFFER_SIZE 64*1024
+
+static int tinygz(int in_fd, int out_fd);
+
+
+int main(int argc, char *argv[]) {
+    int out_fd = atoi(argv[1]);
+    return tinygz(STDIN_FILENO, out_fd);
+}
+
+
+static int tinygz(int in_fd, int out_fd) {
+    gzFile gz = gzdopen(out_fd, "ab4");
+    if (gz == NULL)
+        goto err;
+
+    char read_buf[READ_BUFFER_SIZE];
+
+    for (;;) {
+        ssize_t bytes_read = read(in_fd, read_buf, READ_BUFFER_SIZE);
+        if (bytes_read == 0) {
+            goto done;
+        } else if (bytes_read < 0) {
+            if (errno == EAGAIN) {
+                continue;
+            } else {
+                perror("read()");
+                goto err;
+            }
+        } else {
+            size_t bytes_written;
+            while (bytes_read > 0) {
+                bytes_written = gzwrite(gz, read_buf, bytes_read);
+                if (bytes_written == 0) {
+                    perror("gzwrite()");
+                    goto err;
+                } else {
+                    bytes_read -= bytes_written;
+                }
+            }
+        }
+    }
+
+    assert(0 && "unreachable");
+
+done:
+    return gzclose_w(gz) == Z_OK ? 0 : 1;
+
+err:
+    if (gz != NULL)
+        gzclose_w(gz);
+    return 1;
+}
