Index: benchmark/io/http/main.cfa
===================================================================
--- benchmark/io/http/main.cfa	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/main.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -33,11 +33,17 @@
 //============================================================================================='
 
-thread StatsPrinter {};
+thread StatsPrinter {
+	Worker * workers;
+	int worker_cnt;
+};
 
 void ?{}( StatsPrinter & this, cluster & cl ) {
 	((thread&)this){ "Stats Printer Thread", cl };
+	this.worker_cnt = 0;
 }
 
 void ^?{}( StatsPrinter & mutex this ) {}
+
+#define eng3(X) (ws(3, 3, unit(eng( X ))))
 
 void main(StatsPrinter & this) {
@@ -51,4 +57,42 @@
 
 		print_stats_now( *active_cluster(), CFA_STATS_READY_Q | CFA_STATS_IO );
+		if(this.worker_cnt != 0) {
+			uint64_t tries = 0;
+			uint64_t calls = 0;
+			uint64_t header = 0;
+			uint64_t splcin = 0;
+			uint64_t splcot = 0;
+			struct {
+				volatile uint64_t calls;
+				volatile uint64_t bytes;
+			} avgrd[zipf_cnts];
+			memset(avgrd, 0, sizeof(avgrd));
+
+			for(i; this.worker_cnt) {
+				tries += this.workers[i].stats.sendfile.tries;
+				calls += this.workers[i].stats.sendfile.calls;
+				header += this.workers[i].stats.sendfile.header;
+				splcin += this.workers[i].stats.sendfile.splcin;
+				splcot += this.workers[i].stats.sendfile.splcot;
+				for(j; zipf_cnts) {
+					avgrd[j].calls += this.workers[i].stats.sendfile.avgrd[j].calls;
+					avgrd[j].bytes += this.workers[i].stats.sendfile.avgrd[j].bytes;
+				}
+			}
+
+			double ratio = ((double)tries) / calls;
+
+			sout | "----- Worker Stats -----";
+			sout | "sendfile  : " | calls | "calls," | tries | "tries (" | ratio | " try/call)";
+			sout | "            " | header | "header," | splcin | "splice in," | splcot | "splice out";
+			sout | " - zipf sizes:";
+			for(i; zipf_cnts) {
+				double written = avgrd[i].calls > 0 ? ((double)avgrd[i].bytes) / avgrd[i].calls : 0;
+				sout | "        " | zipf_sizes[i] | "bytes," | avgrd[i].calls | "shorts," | written | "written";
+			}
+		}
+		else {
+			sout | "No Workers!";
+		}
 	}
 }
@@ -218,4 +262,6 @@
 			{
 				Worker * workers = anew(options.clopts.nworkers);
+				cl[0].prnt->workers = workers;
+				cl[0].prnt->worker_cnt = options.clopts.nworkers;
 				for(i; options.clopts.nworkers) {
 					// if( options.file_cache.fixed_fds ) {
@@ -311,2 +357,5 @@
 	}
 }
+
+const size_t zipf_sizes[] = { 102, 204, 307, 409, 512, 614, 716, 819, 921, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 20480, 30720, 40960, 51200, 61440, 71680, 81920, 92160, 102400, 204800, 307200, 409600, 512000, 614400, 716800, 819200, 921600 };
+static_assert(zipf_cnts == sizeof(zipf_sizes) / sizeof(zipf_sizes[0]));
Index: benchmark/io/http/parhttperf
===================================================================
--- benchmark/io/http/parhttperf	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/parhttperf	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -6,8 +6,8 @@
 
 mkdir -p out
-rm -v out/*
+rm out/*
+echo "httperf --client [0-$(($NTHREADS - 1))]/$NTHREADS $@ > out/result.[0-$(($NTHREADS - 1))].out"
 for ((i=0; i<$NTHREADS; i++))
 do
-	# echo "httperf --client $i/$NTHREADS $@ > out/result.$i.out"
 	httperf --client $i/$NTHREADS $@ > out/result.$i.out &
 done
Index: benchmark/io/http/protocol.cfa
===================================================================
--- benchmark/io/http/protocol.cfa	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/protocol.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -24,4 +24,5 @@
 
 #include "options.hfa"
+#include "worker.hfa"
 
 #define PLAINTEXT_1WRITE
@@ -156,5 +157,4 @@
 
 		count -= ret;
-		offset += ret;
 		size_t in_pipe = ret;
 		SPLICE2: while(in_pipe > 0) {
@@ -266,5 +266,5 @@
 }
 
-static inline int wait_and_process(header_g & this) {
+static inline int wait_and_process(header_g & this, sendfile_stats_t & stats) {
 	wait(this.f);
 
@@ -295,4 +295,6 @@
 	}
 
+	stats.header++;
+
 	// It must be a Short read
 	this.len  -= this.f.result;
@@ -306,4 +308,5 @@
 	io_future_t f;
 	int fd; int pipe; size_t len; off_t off;
+	short zipf_idx;
 	FSM_Result res;
 };
@@ -314,4 +317,12 @@
 	this.len = len;
 	this.off = 0;
+	this.zipf_idx = -1;
+	STATS: for(i; zipf_cnts) {
+		if(len <= zipf_sizes[i]) {
+			this.zipf_idx = i;
+			break STATS;
+		}
+	}
+	if(this.zipf_idx < 0) mutex(serr) serr | "SPLICE IN" | len | " greated than biggest zipf file";
 }
 
@@ -329,5 +340,5 @@
 }
 
-static inline int wait_and_process(splice_in_t & this) {
+static inline int wait_and_process(splice_in_t & this, sendfile_stats_t & stats ) {
 	wait(this.f);
 
@@ -345,4 +356,6 @@
 			return error(this.res, -ECONNRESET);
 		}
+		mutex(serr) serr | "SPLICE IN got" | error | ", WTF!";
+		return error(this.res, -ECONNRESET);
 	}
 
@@ -357,4 +370,8 @@
 		return done(this.res);
 	}
+
+	stats.splcin++;
+	stats.avgrd[this.zipf_idx].calls++;
+	stats.avgrd[this.zipf_idx].bytes += this.f.result;
 
 	// It must be a Short read
@@ -398,5 +415,5 @@
 }
 
-static inline void wait_and_process(splice_out_g & this) {
+static inline void wait_and_process(splice_out_g & this, sendfile_stats_t & stats ) {
 	wait(this.f);
 
@@ -414,4 +431,6 @@
 			return error(this, -ECONNRESET);
 		}
+		mutex(serr) serr | "SPLICE OUT got" | error | ", WTF!";
+		return error(this, -ECONNRESET);
 	}
 
@@ -428,4 +447,6 @@
 
 SHORT_WRITE:
+	stats.splcot++;
+
 	// It must be a Short Write
 	this.len -= this.f.result;
@@ -434,5 +455,6 @@
 }
 
-int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize ) {
+int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize, sendfile_stats_t & stats ) {
+	stats.calls++;
 	#if defined(LINKED_IO)
 		char buffer[512];
@@ -443,4 +465,5 @@
 
 		RETRY_LOOP: for() {
+			stats.tries++;
 			int have = need(header.res) + need(splice_in.res) + 1;
 			int idx = 0;
@@ -461,5 +484,5 @@
 			// we may need to kill the connection if it fails
 			// If it already completed, this is a no-op
-			wait_and_process(splice_in);
+			wait_and_process(splice_in, stats);
 
 			if(is_error(splice_in.res)) {
@@ -469,6 +492,6 @@
 
 			// Process the other 2
-			wait_and_process(header);
-			wait_and_process(splice_out);
+			wait_and_process(header, stats);
+			wait_and_process(splice_out, stats);
 
 			if(is_done(splice_out.res)) {
@@ -490,4 +513,5 @@
 		return len + fsize;
 	#else
+		stats.tries++;
 		int ret = answer_header(fd, fsize);
 		if( ret < 0 ) { close(fd); return ret; }
Index: benchmark/io/http/protocol.hfa
===================================================================
--- benchmark/io/http/protocol.hfa	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/protocol.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -1,3 +1,5 @@
 #pragma once
+
+struct sendfile_stats_t;
 
 enum HttpCode {
@@ -18,5 +20,5 @@
 int answer_plaintext( int fd );
 int answer_empty( int fd );
-int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t count );
+int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t count, struct sendfile_stats_t & );
 
 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len);
Index: benchmark/io/http/worker.cfa
===================================================================
--- benchmark/io/http/worker.cfa	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/worker.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -23,4 +23,14 @@
 	this.pipe[1] = -1;
 	this.done = false;
+
+	this.stats.sendfile.calls = 0;
+	this.stats.sendfile.tries = 0;
+	this.stats.sendfile.header = 0;
+	this.stats.sendfile.splcin = 0;
+	this.stats.sendfile.splcot = 0;
+	for(i; zipf_cnts) {
+		this.stats.sendfile.avgrd[i].calls = 0;
+		this.stats.sendfile.avgrd[i].bytes = 0;
+	}
 }
 
@@ -123,5 +133,5 @@
 
 			// Send the desired file
-			int ret = answer_sendfile( this.pipe, fd, ans_fd, count);
+			int ret = answer_sendfile( this.pipe, fd, ans_fd, count, this.stats.sendfile );
 			if( ret == -ECONNRESET ) break REQUEST;
 
Index: benchmark/io/http/worker.hfa
===================================================================
--- benchmark/io/http/worker.hfa	(revision 3a40df659c2993d7df0f62b96d084fd2878dc6c4)
+++ benchmark/io/http/worker.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
@@ -11,4 +11,19 @@
 //=============================================================================================
 
+extern const size_t zipf_sizes[];
+enum { zipf_cnts = 36, };
+
+struct sendfile_stats_t {
+	volatile uint64_t calls;
+	volatile uint64_t tries;
+	volatile uint64_t header;
+	volatile uint64_t splcin;
+	volatile uint64_t splcot;
+	struct {
+		volatile uint64_t calls;
+		volatile uint64_t bytes;
+	} avgrd[zipf_cnts];
+};
+
 thread Worker {
 	int pipe[2];
@@ -18,4 +33,7 @@
 	int flags;
 	volatile bool done;
+	struct {
+		sendfile_stats_t sendfile;
+	} stats;
 };
 void ?{}( Worker & this);
