Giter VIP home page Giter VIP logo

haywire's Introduction

Join us on #haywire on Freenode Build Status

Haywire

Haywire is an asynchronous HTTP server framework written in C. The goal of Haywire is to learn how to create a server with a minimal feature set that can handle a high rate of requests and connections with as low of latency and resource usage as possible.

Haywire uses the event loop based libuv platform layer that node.js is built on top of (also written in C). libuv abstracts IOCP on Windows and epoll/kqueue/event ports/etc. on Unix systems to provide efficient asynchronous I/O on all supported platforms.

Haywire isn't very useful yet but I wanted to open source it from the very beginning. I started experimenting with a HTTP server for Dazzle queries and I decided I would split it into its own project.

Features

  • Cross platform (Windows, Linux, OSX)
  • HTTP keep-alive
  • HTTP pipelining
  • Non-blocking I/O
  • SO_REUSEPORT multi-process and multi-threaded load balancing across CPU cores.

Plans or Ideas

  • HTTP handler routing
  • SPDY support
  • Export an API that is easily consumable by other languages like on the JVM (Java, etc) and the CLR (C#, etc)

Contributions

Feel free to join in if you feel like helping progress Haywire. I'm open to new ideas and would love to work with some people instead of by myself!

Dependencies

apt-get install git gcc make cmake automake autoconf libssl-dev libtool

Compiling on Linux

./make.sh

Compiling on Mac OSX

brew install automake
brew install libtool
brew install openssl
./make.sh

Compiling on Windows

These instructions are old but may still work. We need to make Windows support in make.sh.

Open the Developer Command Prompt for Visual Studio

build.bat

Benchmarks

Bare metal Rackspace instance
Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz 20 physical cores

Throughput

../bin/wrk/wrk --script ./pipelined_get.lua --latency -d 5m -t 40 -c 760 http://server:8000 -- 32

Running 5m test @ http://server:8000
  40 threads and 760 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.04ms    5.38ms 389.00ms   92.75%
    Req/Sec   233.38k    48.72k  458.99k    86.19%
  Latency Distribution
     50%    1.26ms
     75%    1.96ms
     90%    4.09ms
     99%    0.00us
  2781077938 requests in 5.00m, 409.23GB read
Requests/sec: 9,267,161.41
Transfer/sec:      1.36GB

Latency distribution with coordinated omission at 3.5 million requests/second

../bin/wrk2/wrk --script ./pipelined_get.lua --latency -d 10s -t 80 -c 512 -R 3500000 http://server:8000 -- 32

Running 10s test @ http://server:8000
  80 threads and 512 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.82ms    3.00ms  64.86ms   94.17%
    Req/Sec       -nan      -nan   0.00      0.00%
  Latency Distribution (HdrHistogram - Recorded Latency)
 50.000%    1.18ms
 75.000%    1.62ms
 90.000%    2.34ms
 99.000%   16.75ms
 99.900%   33.12ms
 99.990%   44.70ms
 99.999%   52.99ms
100.000%   64.89ms

----system---- ----total-cpu-usage---- ------memory-usage----- --io/total- -dsk/total- -net/total- ---system-- -pkt/total- ----tcp-sockets----
     time     |usr sys idl wai hiq siq| used  buff  cach  free| read  writ| read  writ| recv  send| int   csw |#recv #send|lis act syn tim clo
03-12 18:58:10|  0   0  99   0   0   0| 712M 95.3M 1203M  124G|0.05  0.22 | 684B   10k|   0     0 |5066  1368 |   0     0 |  3   2   0   0   0
03-12 18:58:11|  0   0 100   0   0   0| 711M 95.3M 1203M  124G|   0     0 |   0     0 |5538B 1588B| 425   975 |92.0  2.00 |  3   2   0   0   0
03-12 18:58:12|  5   2  92   0   0   1| 725M 95.3M 1203M  124G|   0     0 |   0     0 |  85M  285M| 220k  112k| 127k  226k|  3 482   0   0   1
03-12 18:58:13| 10   4  85   0   0   1| 724M 95.3M 1203M  124G|   0  2.00 |   0    32k| 166M  556M| 427k  173k| 243k  438k|  3 482   0   0   1
03-12 18:58:14| 10   4  85   0   0   1| 725M 95.3M 1203M  124G|   0     0 |   0     0 | 165M  555M| 435k  172k| 243k  438k|  3 482   0   0   1
03-12 18:58:15| 10   4  85   0   0   1| 723M 95.3M 1203M  124G|   0     0 |   0     0 | 166M  555M| 440k  172k| 243k  438k|  3 482   0   0   1
03-12 18:58:16| 10   4  86   0   0   1| 724M 95.3M 1203M  124G|   0     0 |   0     0 | 166M  555M| 415k  172k| 243k  438k|  3 482   0   0   1
03-12 18:58:17| 10   4  85   0   0   1| 723M 95.3M 1203M  124G|   0     0 |   0     0 | 165M  555M| 404k  172k| 243k  438k|  3 482   0   0   1
03-12 18:58:18| 10   4  85   0   0   1| 724M 95.3M 1203M  124G|   0  5.00 |   0    24k| 165M  555M| 404k  171k| 243k  438k|  3 482   0   0   1
03-12 18:58:19| 10   4  85   0   0   1| 724M 95.3M 1203M  124G|   0     0 |   0     0 | 166M  555M| 411k  171k| 243k  438k|  3 482   0   0   1
03-12 18:58:20| 10   4  85   0   0   1| 723M 95.3M 1203M  124G|   0     0 |   0     0 | 166M  555M| 412k  170k| 244k  438k|  3 482   0   0   1
03-12 18:58:21| 10   4  85   0   0   1| 722M 95.3M 1203M  124G|   0     0 |   0     0 | 166M  555M| 411k  171k| 244k  438k|  3 482   0   0   1
03-12 18:58:22|  5   2  93   0   0   1| 724M 95.3M 1203M  124G|   0     0 |   0     0 |  76M  256M| 190k   81k| 113k  202k|  3   2   0   0 391

Users of Haywire

There's a production system running Haywire that serves 700 million requests a day from an Aerospike cluster with 2ms or lower response times.

pyrs Python handlers for Haywire.

haywire's People

Contributors

cww avatar georgehahn avatar hyc avatar jbcrail avatar jbogard avatar kellabyte avatar michaelhood avatar mmicko avatar nmdguerreiro avatar nschonni avatar pphaneuf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haywire's Issues

Using uname to get OS platform gives inconsistent behavior

If a user already has uname on their path, the return value from uname may be inconsistent.

On my computer, uname -s returns:
"windows32" with the version included on my path from gnuwin32 (highest precedence)
"MINGW32_NT-6.2" with the version included on my path from git (next in line)
"Windows_NT" with the version included with Haywire (lowest precedence)

Would testing for !Unix would be an acceptable fix?

The techempower example crashes for longer messages

Hi,

I tried compiling the techempower benchmarks with the following patch:

(temp-python)[jlouis@daemonette Haywire]$ git diff
diff --git a/src/samples/techempower_benchmark/program.c b/src/samples/techempower_benchmark/program.c
index e0db9c8..41901ac 100644
--- a/src/samples/techempower_benchmark/program.c
+++ b/src/samples/techempower_benchmark/program.c
@@ -26,7 +26,7 @@ void get_plaintext(http_request* request, hw_http_response* response, void* user
     SETSTRING(content_type_value, "text/plain");
     hw_set_response_header(response, &content_type_name, &content_type_value);

-    SETSTRING(body, "Hello, World!");
+    SETSTRING(body, "CHAPTER I. Down the Rabbit-Hole  Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, <and what is the use of a book,> thought Alice <without pictures or conversations?> So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her. There was nothing so very remarkable in that; nor did Alice think it so very much out of the way to hear the Rabbit say to itself, <Oh dear! Oh dear! I shall be late!> (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually took a watch out of its waistcoat-pocket, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge. In another moment down went Alice after it, never once considering how in the world she was to get out again. The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards......");
     hw_set_body(response, &body);

     if (request->keep_alive)

And then a single curl against the /plaintext endpoint results in:

*** Error in `./builds/unix/release/techempower_benchmark': double free or corruption (!prev): 0x00007
f5d34013f00 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x7198e)[0x7f5df90a698e]
/usr/lib/libc.so.6(+0x76dee)[0x7f5df90abdee]
/usr/lib/libc.so.6(+0x775cb)[0x7f5df90ac5cb]
./builds/unix/release/techempower_benchmark[0x405dbc]
./builds/unix/release/techempower_benchmark[0x410b8a]
./builds/unix/release/techempower_benchmark[0x411511]
./builds/unix/release/techempower_benchmark[0x40cd93]
./builds/unix/release/techempower_benchmark[0x4076ee]
./builds/unix/release/techempower_benchmark[0x412b47]

I had expected the first 2053 bytes of Alice in Wonderland to magically come out of the woodwork, and it also does. Curl returns it correctly. But haywire crashes with the above abort right after.

I also tried a really hacked solution where I used create_string to heap-allocate the string and refer to it as a global value because I had a hunch it was due to some stack allocation trouble. But it still fails with the above error.

This is on an ArchLinux, which is fairly recent. Can anyone reproduce this one on other architectures?

Graceful shutdown

Haywire should handle the SIGTERM signal by:

  • Finishing pending requests
  • Closing all connections after pending requests have been served
  • Stopping all threads (if in multi-threaded mode)
  • Closing IPC pipes (if in multi-threaded mode)

Memory leaks with HTTP 1.0 non-keep-alive connections

Haywire seems to be leak free when using Wrk benchmark tool but using Apache Bench or HP HttpPerf leaks memory. It's easier to reproduce with HP HttpPerf because Haywire assumes HTTP 1.1 and doesn't yet support switching between HTTP 1.0 and 1.1.

Reproduce with HP HttpPerf

Compile Haywire.

git clone https://github.com/kellabyte/Haywire.git
./build.sh

Benchmark using HP HttpPerf. Download the tarball.

./configure
make
make install

Run Haywire in Valgrind

valgrind --tool=memcheck --leak-check=full ./builds/unix/debug/hello_world

Run HttpPerf benchmark

httperf --server=localhost --port=8000 --num-conns=1 --num-calls=1

After a few seconds after the benchmark ends CTRL-C to get the Valgrind output.

==26418== 
==26418== HEAP SUMMARY:
==26418==     in use at exit: 527 bytes in 5 blocks
==26418==   total heap usage: 19 allocs, 14 frees, 133,266 bytes allocated
==26418== 
==26418== 5 bytes in 1 blocks are definitely lost in loss record 1 of 5
==26418==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26418==    by 0x40886A: http_request_on_header_field (http_request.c:64)
==26418==    by 0x40638C: http_parser_execute (http_parser.c:1334)
==26418==    by 0x4035F7: http_stream_on_read (http_server.c:113)
==26418==    by 0x411BD8: uv__read (stream.c:1023)
==26418==    by 0x412016: uv__stream_io (stream.c:1118)
==26418==    by 0x41791E: uv__io_poll (linux-core.c:211)
==26418==    by 0x40A4BB: uv_run (core.c:317)
==26418==    by 0x40347E: hw_http_open (http_server.c:71)
==26418==    by 0x403300: main (program.c:26)
==26418== 
==26418== 10 bytes in 1 blocks are definitely lost in loss record 2 of 5
==26418==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26418==    by 0x408915: http_request_on_header_value (http_request.c:80)
==26418==    by 0x4068D4: http_parser_execute (http_parser.c:1426)
==26418==    by 0x4035F7: http_stream_on_read (http_server.c:113)
==26418==    by 0x411BD8: uv__read (stream.c:1023)
==26418==    by 0x412016: uv__stream_io (stream.c:1118)
==26418==    by 0x41791E: uv__io_poll (linux-core.c:211)
==26418==    by 0x40A4BB: uv_run (core.c:317)
==26418==    by 0x40347E: hw_http_open (http_server.c:71)
==26418==    by 0x403300: main (program.c:26)
==26418== 
==26418== LEAK SUMMARY:
==26418==    definitely lost: 15 bytes in 2 blocks
==26418==    indirectly lost: 0 bytes in 0 blocks
==26418==      possibly lost: 0 bytes in 0 blocks
==26418==    still reachable: 512 bytes in 3 blocks
==26418==         suppressed: 0 bytes in 0 blocks
==26418== Reachable blocks (those to which a pointer was found) are not shown.
==26418== To see them, rerun with: --leak-check=full --show-reachable=yes
==26418== 
==26418== For counts of detected and suppressed errors, rerun with: -v
==26418== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

Non-pipelined requests are too slow

Summary

When benchmarking 1024 connections requests/second performance seems much lower than they should be.

Benchmarking

./builds/unix/debug/haywire_hello_world 8000 8 1

wrk --latency -d 10s -t 8 -c 1024 http://server:8000

Running 10s test @ http://server:8000
  8 threads and 1024 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    10.46ms   19.62ms 255.42ms   90.68%
    Req/Sec    21.75k     8.34k   60.51k    76.56%
  Latency Distribution
     50%    4.77ms
     75%    7.43ms
     90%   27.84ms
     99%   98.22ms
  1718779 requests in 10.10s, 258.99MB read
  Socket errors: connect 11, read 0, write 0, timeout 0
Requests/sec: 170,213.77
Transfer/sec:     25.65MB

170,000 requests/second is too slow and 25MB/s is way lower than the network can handle.

Where can we get gains from in the perf report below?

khash illegal instruction

I've got problems running code which was compiling on my previous PC and now it causes a
"Illegal instruction (core dumped)".

==3406== Memcheck, a memory error detector
==3406== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3406== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==3406== Command: ./src/pxdon/pxdon
==3406== 
vex amd64->IR: unhandled instruction bytes: 0xC5 0xF9 0x57 0xC0 0xC4 0xE1 0xFB 0x2A
vex amd64->IR:   REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR:   VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE
vex amd64->IR:   PFX.66=0 PFX.F2=0 PFX.F3=0
==3406== valgrind: Unrecognised instruction at address 0x50627df.
==3406==    at 0x50627DF: kh_resize_string_hashmap (http_server.c:37)
==3406==    by 0x5062D5B: kh_put_string_hashmap (http_server.c:37)
==3406==    by 0x506313F: set_route (http_server.c:78)
==3406==    by 0x50631D4: hw_http_add_route (http_server.c:92)
==3406==    by 0x4151C0: pxdon::ProxyChecker::bind(std::string, int) (proxy_checker.cpp:202)
==3406==    by 0x417ED7: pxdon::Explorer::start() (explorer.cpp:137)
==3406==    by 0x41A71F: main (main.cpp:37)
==3406== Your program just tried to execute an instruction that Valgrind
==3406== did not recognise.  There are two possible reasons for this.
==3406== 1. Your program has a bug and erroneously jumped to a non-code
==3406==    location.  If you are running Memcheck and you just saw a
==3406==    warning about a bad jump, it's probably your program's fault.
==3406== 2. The instruction is legitimate but Valgrind doesn't handle it,
==3406==    i.e. it's Valgrind's fault.  If you think this is the case or
==3406==    you are not sure, please let us know and we'll try to fix it.
==3406== Either way, Valgrind will now raise a SIGILL signal which will
==3406== probably kill your program.
==3406== 
==3406== Process terminating with default action of signal 4 (SIGILL)
==3406==  Illegal opcode at address 0x50627DF
==3406==    at 0x50627DF: kh_resize_string_hashmap (http_server.c:37)
==3406==    by 0x5062D5B: kh_put_string_hashmap (http_server.c:37)
==3406==    by 0x506313F: set_route (http_server.c:78)
==3406==    by 0x50631D4: hw_http_add_route (http_server.c:92)
==3406==    by 0x4151C0: pxdon::ProxyChecker::bind(std::string, int) (proxy_checker.cpp:202)
==3406==    by 0x417ED7: pxdon::Explorer::start() (explorer.cpp:137)
==3406==    by 0x41A71F: main (main.cpp:37)
==3406== 
==3406== HEAP SUMMARY:
==3406==     in use at exit: 62,146 bytes in 269 blocks
==3406==   total heap usage: 314 allocs, 45 frees, 98,209 bytes allocated
==3406== 
==3406== LEAK SUMMARY:
==3406==    definitely lost: 0 bytes in 0 blocks
==3406==    indirectly lost: 0 bytes in 0 blocks
==3406==      possibly lost: 701 bytes in 13 blocks
==3406==    still reachable: 61,445 bytes in 256 blocks
==3406==         suppressed: 0 bytes in 0 blocks
==3406== Rerun with --leak-check=full to see details of leaked memory
==3406== 
==3406== For counts of detected and suppressed errors, rerun with: -v
==3406== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Illegal instruction (core dumped)

I was getting error

[100%] Built target haywire_core
Linking C shared library libhaywire_shared.so
/usr/bin/ld: CMakeFiles/haywire_core.dir/src/haywire/configuration/configuration.c.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
CMakeFiles/haywire_core.dir/src/haywire/configuration/configuration.c.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
CMakeFiles/haywire_shared.dir/build.make:84: recipe for target 'libhaywire_shared.so' failed
make[2]: *** [libhaywire_shared.so] Error 1
CMakeFiles/Makefile2:95: recipe for target 'CMakeFiles/haywire_shared.dir/all' failed
make[1]: *** [CMakeFiles/haywire_shared.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2

so the library is compiled with -fPIC flag.
All that is happening on freshly installed fedora.
gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC)

What do You think could be source of the problem?

haywire_hello_world crashes under benchmark testing in Ubuntu 13.10

Just cloned code from github, run build.sh
After building, start haywire_hello_world debug version
And run ab -n 200000 -c 132 http://localhost:8000/

haywire_hello_world always craches after completed 45k requests

root@lab199:~/work/nm_cpp/Haywire/builds/unix/debug# ./haywire_hello_world
Added route /stats
Added route /
Listening on 0.0.0.0:8000
haywire_hello_world: lib/libuv/src/unix/stream.c:996: uv__read: Assertion buf.base != ((void *)0)' failed. haywire_hello_world: lib/libuv/src/unix/stream.c:996: uv__read: Assertionbuf.base != ((void *)0)' failed.
Aborted (core dumped)

haywire_hello_world fails under benchmark

On Mac OS X 10.9 I followed the build instructions using 6f162f1. Haywire built okay, and I ran the hello world sample server - it started fine. I made a single curl request - it ran fine. I then used the ab command from the benchmarking document (ab -n 100000 -c 32 -k http://127.0.0.1:8000/) and then it crashed like so:

$ ./builds/unix/debug/haywire_hello_world
Added route /stats
Added route /
Listening on 0.0.0.0:8000
connections_created_total: 2
connections_destroyed_total: 1
requests_created_total: 2
requests_destroyed_total: 1

haywire_hello_world(43163,0xb0103000) malloc: *** mach_vm_map(size=8388608) failed (error code=3)
*** error: can't allocate region securely
*** set a breakpoint in malloc_error_break to debug
Assertion failed: (buf.base != NULL), function uv__read, file lib/libuv/src/unix/stream.c, line 996.
[1]    43163 abort      ./builds/unix/debug/haywire_hello_world
$ ab -n 100000 -c 32 -k http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
apr_socket_recv: Connection refused (61)
Total of 54219 requests completed

I tried this twice and the total number of requests was not the same, but it's always around 54000 requests. Any more information I can provide to help diagnose this?

No License?

It appears that there isn't an explicit license for Haywire; Could you clarify your intended license and ideally include it?

Fix buffer management not handling exceeding the libuv buffer size

Haywire isn't using libuv and buffers passed to it correctly. In the case a really large request comes in that requires 2 libuv alloc_cb() calls we aren't tracking multiple buffers.

This surfaces 2 problems:

  1. Large requests aren't handled properly.
  2. During pipelined benchmarks with 64 pipelined requests the buffer can get filled and cause the same problem.

These will show up as non-200 errors.

../bin/wrk/wrk --script ./pipelined_get.lua --latency -d 10s -t 10 -c 512 http://server:8000/bar/foo2 -- 64
Running 10s test @ http://server:8000/bar/foo2
  10 threads and 512 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.53ms    7.41ms 138.98ms   90.05%
    Req/Sec   391.46k    73.43k  530.99k    54.40%
  Latency Distribution
     50%    3.57ms
     75%    6.54ms
     90%   12.88ms
     99%    0.00us
  39188258 requests in 10.08s, 6.42GB read
  Socket errors: connect 0, read 8, write 0, timeout 0
  Non-2xx or 3xx responses: 290
Requests/sec: 3888292.59
Transfer/sec:    652.57MB

Another way to reproduce is:

dd if=/dev/urandom of=test.dat bs=1048576 count=1
curl -D @test.dat http://server:8000 

CMake build

I started building a CMake version of the build so that I can move away from gyp. I don't think the current directory structure works since I don't think CMake can handle multiple projects very well. Most googling I saw requires you to create multiple CMake builds.

So let's investigate what is needed to move to CMake.

Respond with HTTP 413 Entity Too Large if request line and headers is too large.

This thread contains some good information. NGINX uses the OS page size which probably is the best for hardware optimization.

Summary from the StackOverFlow thread

As vartec says above, the HTTP spec does not define a limit, however many servers do by default. This means, practically speaking, the lower limit is 8K. For most servers, this limit applies to the sum of the request line and ALL header fields (so keep your cookies short).

Apache 2.0, 2.2: 8K
nginx: 4K - 8K
IIS: varies by version, 8K - 16K
Tomcat: varies by version, 8K - 48K (?!)

It's worth noting that nginx uses the system page size by default, which is 4K on most systems. You can check with this tiny program:

pagesize.c:

#include <unistd.h>
#include <stdio.h>

int main() {
    int pageSize = getpagesize();
    printf("Page size on your system = %i bytes\n", pageSize);
    return 0;
}

Compile with gcc -o pagesize pagesize.c then run ./pagesize. My ubuntu server from Linode dutifully informs me the answer is 4k.

Fix the Windows build

Last time I checked Haywire's multi-threaded support doesn't work on Windows due to a libuv bug that I had trouble tracking down.

Haywire should build on Windows and at least support single threaded mode.

Wrk doesn't compile on OSX

OSX El Capitan changes some things with OpenSSL and if you've installed it via brew then you need to do the following to get the headers to be recognized again.

brew link openssl --force

Handle HTTP 1.0 and HTTP 1.1 keep-alive properly

Right now Haywire assumes HTTP keep-alive at all times and doesn't pay attention to the connection header or the HTTP version. It needs to start respecting them. Below are the details of how to handle HTTP 1.0 and HTTP 1.1 properly.

HTTP 1.0

  • If a client like Apache Bench that is HTTP 1.0 doesn't provide the connection: keep-alive header the socket connection should be closed after replying.
  • If the client provides the connection: keep-alive header the socket should remain open.

HTTP 1.1

  • In HTTP 1.1 connections are implied to be keep-alive so don't close the socket unless the client provides the Connection: close header.

Request should only be free'd after writing response

The request is currently free'd after executing the route callback, but ideally that should only happen after writing the response back to the client.

That was attempted in #79, but it turned out to cause sporadical crashes and needs more looking into. Maybe the "write finished" callback is executed more than once per request?

Benchmark server

We've been benchmarking performance mostly based on hello_world, but that is a very simplistic server.

We need to create a benchmark that includes at least:

  • Multiple routes
  • Multiple verbs (GET/POST/etc)
  • Multiple sizes of headers and bodies.
  • Multiple sizes of responses

Note: Windows Builds

I was able to build a VS2012 project with the following command line:

Haywire [master +8 ~1 -0 !]> python .\bin\gyp\gyp .\haywire.gyp -Dtarget_arch=ia32 -Dlibrary=static_library --depth=3

The generated SLN built and the target executable seemed functional.

Headers get mangled when a high rate of requests coming from multiple connections

http_request.c uses a global variable called last_was_value to track if the last part read from a header was the value and to treat the next fragment as a key. This code was left over from when Haywire was single threaded but once multiple event loop fan-out was implemented this variable got forgotten to be scoped at the connection level. This means header parsing can get screwed up as connections affect other connections parser state.

The fix is to move last_was_value to the http_connection struct.

Not handling HTTP 1.1 keep-alive properly

HTTP 1.1 keep-alive is default and Connection: close needs to be defined for a connection to be closed after a request.

Also to note, this should not be implemented in src/samples/hello_world/program.c as it is right now. This should be built into Haywire. Haywire currently is not specific to any HTTP version but that should change so that it can handle these things internally.

Thanks to @darrelmiller for pointing this out.

Default configuration

We currently have to initialize configuration with all the values in the examples. Similarly, user code will have to set all parameters to avoid unpredictable behaviour.

Instead, we should provide a hw_init_config function that allocates memory for configuration and sets all parameters to their default values (e.g. listen backlog = SOMAXCONN, thread_count = 0, tcp nodelay = off, tcp port = 8000, etc).

Make header key comparisons case insensitive

RFC 7230 says that HTTP header fields should be case insensitive. Haywire normalizes headers to lower case.

Request

curl -v http://localhost:8000
* Rebuilt URL to: http://localhost:8000/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.43.0
> Accept: */*
>

Currently if hw_get_header() is called to get the header named Host it will fail to find the header. If you use host it will work.

Cannot Parse Params In Url

hw_http_add_route add a route in hash map by full text, cannot support url such as /Sample?x=117&y=38
suggest to add some spilt code in http_request_on_message_complete before get_route_callback

Error building on Windows 2012 R2 Standard (x64) and MVSC2015

Hello,
I have tried to compile haywire on Windows thought the Developer Command Prompt for Visual Studio and the "build.bat" file. However, I have found a set of errors related to "unresolved external symbol", which is similar to #76 closed issue. This is the relevant output part:

`"C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire.sln" (destino predeterminado) (1) ->
"C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_hello_world.vcxproj.metaproj" (destino predeterminado) (4) ->
"C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj.metaproj" (destino predeterminado) (5) ->
"C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj" (destino predeterminado) (6) ->
(Link destino) ->
http_request.obj : error LNK2019: unresolved external symbol http_request_buffer_mark referenced in function http_request_on_message_complete [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_request.obj : error LNK2019: unresolved external symbol http_request_buffer_pin referenced in function http_request_on_url [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_request.obj : error LNK2019: unresolved external symbol http_request_buffer_reassign_pin referenced in function http_request_save_current_header [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_request.obj : error LNK2019: unresolved external symbol http_request_buffer_locate referenced in function http_request_save_current_header [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_init referenced in function create_http_connection [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_consume referenced in function http_stream_on_read_http_parser [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_sweep referenced in function http_stream_on_read_http_parser [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_alloc referenced in function http_stream_on_alloc [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_chunk referenced in function http_stream_on_alloc [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
http_server.obj : error LNK2019: unresolved external symbol http_request_buffer_destroy referenced in function free_http_connection [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]
C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\builds\windows\debug\haywire_shared\haywire.dll : fatal error LNK1120: 10 unresolved externals [C:\Users\Administrador\Desktop\HTTP Server c\haywire-master\haywire_shared.vcxproj]

159 Advertencia(s)
11 Errores

`
I also attached two txt files with the whole output from "build.bat", MVSC2015 to provide more information about the issue; and the haywire-master.zip file downloaded today 18th March 2016.

Kind regards,

ipueyo.

Output_build_bat.txt
Output_VS2015_haywire_hello_world.txt
haywire-master.zip

What's the first milestone for this project?

You posted on Twitter that you were curious if people would want to help work on Haywire -- and I think that was a resounding "yes" :). However, what I don't see is a roadmap of what's left to be done overall.. or sort of... what defines a good milestone?

Do you have any sort of idea what Haywire v1.0 should look like? Do you think it's worth coming up with some ideas of what it might look like?

Haywire zero-copy

There is some zero-copying in Haywire but not enough. Now that I understand C more and libuv more I suspect we are copying memory when we do not need to in Haywire.

https://github.com/kellabyte/Haywire/blob/master/src/haywire/http_server.c#L248
Here we allocate the memory libuv requests for the TCP reads on the heap and we should be able to use hw_string everywhere and never need to memcpy headers or any HTTP field if we free() this memory at the very end of the request.

Currently we free this buffer after the request callback is complete to the user code but what if the user spawns a thread? We need to offer a free API to users of the library. That way we never need to have any memcpy in Haywire.

Examples of memcpy that could be removed:
https://github.com/kellabyte/Haywire/blob/master/src/haywire/http_request.c#L115
https://github.com/kellabyte/Haywire/blob/master/src/haywire/http_request.c#L141
https://github.com/kellabyte/Haywire/blob/master/src/haywire/http_request.c#L157
https://github.com/kellabyte/Haywire/blob/master/src/haywire/http_server.c#L248

This should reduce some of our most expensive calls of malloc() and memcpy().

Haywire should have a way to track internal memory usage.

Haywire should have a way to track internal allocations, similar to what libphenom does: http://facebook.github.io/libphenom/#memory

The main benefit of something like this is having a centralized way to report on the memory in use by Haywire, in a logical way: number of connection structures allocated, number of response buffers allocated, etc. It also means there would be a way to then report those statistics, at any given time, to the operator. This is useful for development, for debugging, and for normal operation.

Since we're simply wrapping a normal malloc or free, there's nothing allocated-related to have to concern ourselves with, and these functions could have simple prefixes for the Haywire-based versions, which is still simple enough to grok.

Build Failing on Windows (x64, Windows 10, VS 2015)

"C:\Haywire\haywire.sln" (default target) (1) ->
"C:\Haywire\haywire_hello_world.vcxproj.metaproj" (default target) (4) ->
"C:\Haywire\haywire_hello_world.vcxproj" (default target) (7) ->
(Link target) ->
program.obj : error LNK2019: unresolved external symbol opt_config_init refer
enced in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_config_free refer
enced in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_args_free referen
ced in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_config_parse refe
renced in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_flag_bool referen
ced in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_flag_int referenc
ed in function main [C:\Haywire\haywire_hello_world.vcxproj]
program.obj : error LNK2019: unresolved external symbol opt_flag_string refer
enced in function main [C:\Haywire\haywire_hello_world.vcxproj]
C:\Haywire\builds\windows\debug\haywire_hello_world\haywire_hello_world.exe :
fatal error LNK1120: 7 unresolved externals [C:\Haywire\haywire_hello_world.vc
xproj]

134 Warning(s)
8 Error(s)

SSL connections

I'm looking to replace my current web server with a lower level option as IIS and related hosts have proven to be too heavy for my purposes for many reasons.

One obvious gap of this project from the limited documentation as it relates to our requirements is its ability to server requests over SSL (HTTPS). From the documentation available, this ability is not inherently available to date and there's limited if any interest in supporting it.

I'm open to looking into adding such ability, but want to first ensure that doing so aligns with the goals of the project.

Thanks,
M.Babcock

"Listening on" debug print is hardcoded

The "Listening on" address & port debug print doesn't change when the params passed to hw_http_open change.

Fix: line 53 of http_server.c:

printf("Listening on %s:%d\n", ipaddress, port);

Ragel parser

Did y'all give thought to using mongrel's http parser written in Ragel? Or using Ragel to make your own? Wonder how it would affect the benchmarks/correctness...

Reduce malloc() and free() calls

Currently we are spending a lot of time in the new buffer manager code as well as allocating and freeing memory. Let's look into why these are called so much and figure out how we can reduce them. 6 out of the top 13 calls are malloc related.

After

90,182,405  /build/buildd/glibc-2.21/malloc/malloc.c:_int_malloc [/lib/x86_64-linux-gnu/libc-2.21.so]
84,397,847  /build/buildd/glibc-2.21/malloc/malloc.c:_int_free [/lib/x86_64-linux-gnu/libc-2.21.so]
71,316,659  src/haywire/http_request_buffers.c:http_request_buffer_pin [/root/tmp18/haywire/build/hello_world]
63,189,481  src/haywire/http_parser.c:http_parser_execute [/root/tmp18/haywire/build/hello_world]
60,456,718  src/haywire/http_request_buffers.c:http_request_buffer_reassign_pin [/root/tmp18/haywire/build/hello_world]
47,094,829  src/haywire/http_request_buffers.c:http_request_buffer_locate [/root/tmp18/haywire/build/hello_world]
33,124,183  /build/buildd/glibc-2.21/malloc/malloc.c:malloc [/lib/x86_64-linux-gnu/libc-2.21.so]
30,457,235  /build/buildd/glibc-2.21/malloc/malloc.c:free [/lib/x86_64-linux-gnu/libc-2.21.so]
26,760,452  /build/buildd/glibc-2.21/malloc/malloc.c:calloc [/lib/x86_64-linux-gnu/libc-2.21.so]
15,346,372  src/haywire/http_request.c:set_header [/root/tmp18/haywire/build/hello_world]
13,911,569  /build/buildd/glibc-2.21/malloc/malloc.c:malloc_consolidate [/lib/x86_64-linux-gnu/libc-2.21.so]
12,304,079  /build/buildd/glibc-2.21/string/../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:__memcpy_sse2_unaligned [/lib/x86_64-linux-gnu/libc-2.21.so]
11,545,632  src/haywire/route_compare_method.c:hw_route_compare_method [/root/tmp18/haywire/build/hello_world]

A couple thoughts:

  1. Every request has a response struct. Could we combine mallocs for both into one malloc call? We do something similar here.
  2. Do we need to malloc requests and responses? Can we create a pool and reuse? Would this save CPU time? This struct for example.

Some code snippets of where instructions are going.

      .  void http_server_cleanup_write(char* response_string, hw_write_context* write_context, uv_write_t* write_req)
      .  {
215,136      free(response_string);
9,676,581  => /build/buildd/glibc-2.21/malloc/malloc.c:free (71712x)
215,136      free(write_context);
7,668,152  => /build/buildd/glibc-2.21/malloc/malloc.c:free (71712x)
215,136      free(write_req);
10,410,438  => /build/buildd/glibc-2.21/malloc/malloc.c:free (71712x)
      .  }
      .  int http_server_write_response_single(hw_write_context* write_context, hw_string* response)
358,560  {
 71,712      http_connection* connection = write_context->connection;
      .
215,136      if (connection->state == OPEN) {
286,848          uv_write_t *write_req = (uv_write_t *) malloc(sizeof(*write_req) + sizeof(uv_buf_t));
12,872,398  => /build/buildd/glibc-2.21/malloc/malloc.c:malloc (71712x)
 71,712          uv_buf_t *resbuf = (uv_buf_t *) (write_req + 1);
      .
143,424          resbuf->base = response->value;
143,424          resbuf->len = response->length;
      .
 71,712          write_req->data = write_context;
      .
      .          uv_stream_t *stream = (uv_stream_t *) &write_context->connection->stream;
      .
286,848          if (uv_is_writable(stream)) {
286,848  => /root/tmp18/haywire/lib/libuv/src/unix/stream.c:uv_is_writable (71712x)
      .              /* Ensuring that the the response can still be written. */
358,560              uv_write(write_req, stream, resbuf, 1, http_server_after_write);
19,563,750  => /root/tmp18/haywire/lib/libuv/src/unix/stream.c:uv_write (71712x)
      .              /* TODO: Use the return values from uv_write() */
      .          } else {
      .              /* The connection was closed, so we can write the response back, but we still need to free up things */
      .              http_server_cleanup_write(resbuf->base, write_context, write_req);
      .          }
      .      }
      .
      .      return 0;
645,408  }

This malloc really hurts?

        .  hw_http_response hw_create_http_response(http_connection* connection)
  143,424  {
  215,136      http_response* response = malloc(sizeof(http_response));
27,539,899  => /build/buildd/glibc-2.21/malloc/malloc.c:malloc (71712x)
   71,712      response->connection = connection;
  143,424      response->request = connection->request;
  143,424      response->http_major = 1;
  143,424      response->http_minor = 1;
   71,712      response->body.value = NULL;
   71,712      response->body.length = 0;
   71,712      response->number_of_headers = 0;
        .      return response;
  143,424  }
        .  void hw_free_http_response(hw_http_response* response)
        .  {
        .      http_response* resp = (http_response*)response;
  215,136      free(resp);
9,593,776  => /build/buildd/glibc-2.21/malloc/malloc.c:free (71712x)
        .  }

2 more painfull mallocs.

        .  hw_string* create_response_buffer(hw_http_response* response)
  788,832  {
        .      http_response* resp = (http_response*)response;
  286,848      hw_string* response_string = malloc(sizeof(hw_string));
7,956,650  => /build/buildd/glibc-2.21/malloc/malloc.c:malloc (71712x)
  215,136      hw_string* cached_entry = get_cached_request(resp->status_code.value);
22,212,229  => /root/tmp18/haywire/src/haywire/http_response_cache.c:get_cached_request (71712x)
        .      hw_string content_length;
        .
        .      int i = 0;
        .
  358,560      char length_header[] = "Content-Length: ";
        .      int line_sep_size = sizeof(CRLF);
        .
        .      int header_buffer_incr = 512;
  143,424      int body_size = resp->body.length;
        .      int header_size_remaining = header_buffer_incr;
  215,136      int response_size = header_size_remaining + sizeof(length_header) + num_chars(resp->body.length) + 2 * line_sep_size + body_size + line_sep_si$
        .
  286,848      response_string->value = malloc(response_size);
16,125,993  => /build/buildd/glibc-2.21/malloc/malloc.c:malloc (71712x)
        .
   71,712      response_string->length = 0;
  215,136      append_string(response_string, cached_entry);
3,513,888  => /root/tmp18/haywire/src/haywire/hw_string.c:append_string (71712x)
        .
1,003,968      for (i=0; i< resp->number_of_headers; i++)
        .      {
1,434,240          http_header header = resp->headers[i];
        .
        .          header_size_remaining -= header.name.length + 2 + header.value.length + line_sep_size;
  286,848          if (header_size_remaining < 0) {
        .              header_size_remaining += header_buffer_incr * ((-header_size_remaining/header_buffer_incr) + 1);
        .              response_size += header_size_remaining;
        .              response_string->value = realloc(response_string->value, response_size);
        .          }
        .
  430,272          append_string(response_string, &header.name);
4,876,416  => /root/tmp18/haywire/src/haywire/hw_string.c:append_string (143424x)
  430,272          APPENDSTRING(response_string, ": ");
  573,696          append_string(response_string, &header.value);
4,876,416  => /root/tmp18/haywire/src/haywire/hw_string.c:append_string (143424x)
  717,120          APPENDSTRING(response_string, CRLF);
        .      }
        .
        .      /* Add the body */
  143,424      APPENDSTRING(response_string, length_header);
        .
  358,560      string_from_int(&content_length, body_size, 10);
2,796,768  => /root/tmp18/haywire/src/haywire/hw_string.c:string_from_int (71712x)
        .
  143,424      if (body_size > 0) {
  215,136          append_string(response_string, &content_length);
2,868,480  => /root/tmp18/haywire/src/haywire/hw_string.c:append_string (71712x)
        .      }
        .      else {
        .          hw_string zero_content;
        .          zero_content.value = "0";
        .          zero_content.length = 1;
        .          append_string(response_string, &zero_content);
        .      }
        .
  215,136      APPENDSTRING(response_string, CRLF CRLF);
        .
        .      if (body_size > 0)
        .      {
  215,136          append_string(response_string, &resp->body);
2,438,208  => /root/tmp18/haywire/src/haywire/hw_string.c:append_string (71712x)
        .      }
        .      return response_string;
  860,544  }

build fails on OS X 10.11.3 with latest Xcode

I ran the two scripts to build on OS X, and here's how it died. Any suggestions?

Ld build/Debug/hello_world normal x86_64
    cd /Users/yost/p/aerospike/Haywire
    export MACOSX_DEPLOYMENT_TARGET=10.11
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -L/Users/yost/p/aerospike/Haywire/build/Debug -F/Users/yost/p/aerospike/Haywire/build/Debug -filelist /Users/yost/p/aerospike/Haywire/build/haywire.build/Debug/hello_world.build/Objects-normal/x86_64/hello_world.LinkFileList -mmacosx-version-min=10.11 -Wl,-search_paths_first -Wl,-headerpad_max_install_names /Users/yost/p/aerospike/Haywire/build/Debug/libhaywire.a /Users/yost/p/aerospike/Haywire/lib/libuv/.libs/libuv.a -Xlinker -dependency_info -Xlinker /Users/yost/p/aerospike/Haywire/build/haywire.build/Debug/hello_world.build/Objects-normal/x86_64/hello_world_dependency_info.dat -o /Users/yost/p/aerospike/Haywire/build/Debug/hello_world
clang: error: no such file or directory: '/Users/yost/p/aerospike/Haywire/lib/libuv/.libs/libuv.a'

** BUILD FAILED **


The following build commands failed:
    Ld build/Debug/hello_world normal x86_64
(1 failure)
295 Z% brew install libuv
Warning: libuv-1.7.5 already installed
296 Z% 

Win Techempower benchmarks

Win Techempower benchmarks

Don't stop learning until we win. In Round 10 Haywire placed 9th.

Summary

I had the privilege to gain access to the Techempower environment and benchmark Haywire using the same parameters that Round 11 was run with. ulib is the winner of round 11 so I compared Haywire's experimental picohttpparser branch that includes the new HTTP parser with syscall response batching. This is not polished but it is an experimental branch to see how these changes compete.

The machine benchmarked against has 20 physical cores and 20 hyper-threaded cores. I tested Haywire in 20 and 40 thread configurations to see how this changes performance.

Concurrency: 256

ulib

 wrk -H 'Host: localhost' -H 'Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7' -H 'Connection: keep-alive' --latency -d 15 -c 256 --timeout 256 -t 40 http://10.0.3.2:8080/plaintext -s ~/pipeline.lua -- 16

Running 15s test @ http://10.0.3.2:8080/plaintext
  40 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   594.00us    3.17ms 405.57ms   99.33%
    Req/Sec   178.28k    53.42k  403.55k    67.22%
  Latency Distribution
     50%  354.00us
     75%  420.00us
     90%  467.00us
     99%  640.00us
  100721735 requests in 14.98s, 13.51GB read
Requests/sec: 6721980.23
Transfer/sec:      0.90GB

Haywire (20 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   605.36us  260.06us   2.08ms   74.72%
    Req/Sec   157.60k    27.12k  264.89k    66.86%
  Latency Distribution
     50%  536.00us
     75%  766.00us
     90%    0.96ms
     99%    1.57ms
  89564928 requests in 14.99s, 13.18GB read
  Socket errors: connect 0, read 0, write 0, timeout 66
Requests/sec: 5975704.85
Transfer/sec:      0.88GB

Haywire (40 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   269.42us  164.62us   1.56ms   74.87%
    Req/Sec    97.06k    66.96k  357.33k    65.90%
  Latency Distribution
     50%  251.00us
     75%  370.00us
     90%  449.00us
     99%  767.00us
  56847554 requests in 15.99s, 8.37GB read
  Socket errors: connect 0, read 0, write 0, timeout 1060
Requests/sec: 3554615.69
Transfer/sec:    535.61MB

Concurrency: 1024

ulib

 wrk -H 'Host: localhost' -H 'Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7' -H 'Connection: keep-alive' --latency -d 15 -c 1024 --timeout 1024 -t 40 http://10.0.3.2:8080/plaintext -s ~/pipeline.lua -- 16

Running 15s test @ http://10.0.3.2:8080/plaintext
  40 threads and 1024 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.13ms   44.84ms   1.51s    99.55%
    Req/Sec   156.46k    50.43k  413.33k    70.13%
  Latency Distribution
     50%    0.87ms
     75%    1.15ms
     90%    1.46ms
     99%   39.92ms
  88765885 requests in 14.99s, 11.90GB read
  Socket errors: connect 0, read 1, write 0, timeout 0
Requests/sec: 5922041.65
Transfer/sec:    813.27MB

Haywire (20 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 1024 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.64ms  771.11us 213.96ms   93.23%
    Req/Sec   157.78k    11.72k  234.67k    67.85%
  Latency Distribution
     50%    2.49ms
     75%    2.85ms
     90%    3.02ms
     99%    5.41ms
  89539488 requests in 14.99s, 13.18GB read
  Socket errors: connect 0, read 0, write 0, timeout 21
Requests/sec: 5973054.26
Transfer/sec:      0.88GB

Haywire (40 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 1024 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   787.66us    6.03ms   1.46s    99.99%
    Req/Sec   170.01k    47.79k  394.67k    68.75%
  Latency Distribution
     50%  653.00us
     75%    0.88ms
     90%    1.21ms
     99%    1.84ms
  96700770 requests in 14.99s, 14.23GB read
  Socket errors: connect 0, read 0, write 0, timeout 4176
Requests/sec: 6450812.55
Transfer/sec:      0.95GB

Concurrency: 4096

ulib

 wrk -H 'Host: localhost' -H 'Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7' -H 'Connection: keep-alive' --latency -d 15 -c 4096 --timeout 4096 -t 40 http://10.0.3.2:8080/plaintext -s ~/pipeline.lua -- 16

Running 15s test @ http://10.0.3.2:8080/plaintext
  40 threads and 4096 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.29ms   25.53ms   2.47s    90.20%
    Req/Sec   182.33k    29.57k  359.11k    72.88%
  Latency Distribution
     50%    4.89ms
     75%    7.24ms
     90%   28.42ms
     99%   47.94ms
  103143594 requests in 14.98s, 13.83GB read
  Socket errors: connect 0, read 0, write 0, timeout 665
Requests/sec: 6883446.57
Transfer/sec:      0.92GB

Haywire (20 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 4096 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    16.14ms  113.52ms   1.46s    98.71%
    Req/Sec   157.51k    81.82k  400.00k    59.40%
  Latency Distribution
     50%    5.47ms
     75%    7.01ms
     90%    8.91ms
     99%  213.06ms
  89297984 requests in 14.99s, 13.14GB read
  Socket errors: connect 0, read 0, write 0, timeout 12731
Requests/sec: 5958678.53
Transfer/sec:      0.88GB

Haywire (40 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 4096 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    33.71ms  206.60ms   6.46s    98.82%
    Req/Sec   179.26k    91.01k  529.78k    61.22%
  Latency Distribution
     50%    0.94ms
     75%    1.33ms
     90%   10.30ms
     99%    1.45s
  101397506 requests in 14.99s, 14.92GB read
  Socket errors: connect 0, read 0, write 0, timeout 16663
Requests/sec: 6764530.12
Transfer/sec:      1.00GB

Concurrency: 16384

ulib

 wrk -H 'Host: localhost' -H 'Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7' -H 'Connection: keep-alive' --latency -d 15 -c 16384 --timeout 16384 -t 40 http://10.0.3.2:8080/plaintext -s ~/pipeline.lua -- 16

Running 15s test @ http://10.0.3.2:8080/plaintext
  40 threads and 16384 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   109.86ms  780.16ms  12.40s    98.88%
    Req/Sec   166.08k    39.26k  307.31k    78.61%
  Latency Distribution
     50%   28.80ms
     75%   35.62ms
     90%   49.04ms
     99%    4.45s 
  99147082 requests in 14.96s, 13.30GB read
  Socket errors: connect 0, read 0, write 0, timeout 7707
Requests/sec: 6628593.11
Transfer/sec:      0.89GB

Haywire (20 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 16384 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    10.31ms   38.02ms 646.98ms   99.63%
    Req/Sec   147.54k    77.80k  464.00k    79.79%
  Latency Distribution
     50%    7.19ms
     75%    8.47ms
     90%   12.48ms
     99%   17.85ms
  87268400 requests in 14.97s, 12.84GB read
  Socket errors: connect 0, read 0, write 0, timeout 92384
Requests/sec: 5829863.60
Transfer/sec:      0.86GB

Haywire (40 threads)

Running 15s test @ http://10.0.3.2:8000
  40 threads and 16384 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    53.31ms  218.31ms   3.13s    96.84%
    Req/Sec   172.64k    95.18k  531.55k    68.02%
  Latency Distribution
     50%    1.82ms
     75%   17.80ms
     90%  207.12ms
     99%    1.46s
  98645652 requests in 14.98s, 14.52GB read
  Socket errors: connect 0, read 0, write 0, timeout 93786
Requests/sec: 6584461.64
Transfer/sec:      0.97GB

Create a http_response struct

The http_request_callback should probably return a http_response struct not a string. Adding convenience methods for adding headers, body etc will make it easier to use.

Debug Error: haywire_hello_world

i try build it by visual studio 2010... but, i catch a error , when i hw_http_open(3) i catch a assert uv_listen : default: assert(0);

[Discussion] Running the benchmarks

Would it be possible to share instructionson the run sever executable for benchmarking.

Running the TechEmpower_Benchmarks.exe throws this

Unhandled exception at 0x00007FF7B2812C10 in techempower_benchmark.exe: 0xC0000005: Access violation reading location 0x000065FC70D25683.

If there is a handler for this exception, the program may be safely continued.

Is there some configuration that has to be done to get past this?

Also I am unable to repro numbers with helloworld as well.

Issue compiling on OSX

Are there any known issues for osx? I attempted to compile the example hello world and encountered the following error

Undefined symbols for architecture x86_64:
  "_hw_http_add_route", referenced from:
      _main in helloWorld-558610.o
  "_hw_http_open", referenced from:
      _main in helloWorld-558610.o
  "_hw_http_response_send", referenced from:
      _get_root in helloWorld-558610.o
  "_hw_init_with_config", referenced from:
      _main in helloWorld-558610.o
  "_hw_set_body", referenced from:
      _get_root in helloWorld-558610.o
  "_hw_set_http_version", referenced from:
      _get_root in helloWorld-558610.o
  "_hw_set_response_header", referenced from:
      _get_root in helloWorld-558610.o
  "_hw_set_response_status_code", referenced from:
      _get_root in helloWorld-558610.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Allow configuration arguments

Right now you can pass a few arguments to haywire_hello_world executable like port, threads, batch size but this is static in order. It would be nice to have --port --threads --batch-size. This should work in cooperation with the ini config file support that is half assed done right now.

https://github.com/kellabyte/Haywire/blob/master/src/samples/hello_world/program.c#L69
https://github.com/kellabyte/Haywire/blob/master/src/samples/hello_world/haywire_hello_world.conf

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.