--
Sourceforge
https://sourceforge.net/projects/civetweb/
---
You received this message because you are subscribed to the Google Groups "civetweb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to civetweb+unsubscribe@googlegroups.com.
To post to this group, send email to cive...@googlegroups.com.
Visit this group at https://groups.google.com/group/civetweb.
To view this discussion on the web visit https://groups.google.com/d/msgid/civetweb/4da6563f-0ba1-4584-885f-159f42026da2%40googlegroups.com.
I’ve been busy with creating a new release, and with New Year’s vacation, so I could not do some tests earlier.
Why test first?
A lot of people do not know or understand the difference between a process and a thread (I’m using the same terms as the Windows API here), lots of internet articles and even some “standard literature” sometimes get these things mixed up. I’m not claiming you (= anyone who posted here) does not know the difference, my claim is, a lot of the literature is bad in this respect. The cost of a process and a thread is vastly different. And anyway, some real comparison is more useful than some literature study.
Test candidates?
A full test can only be done with fully operational servers.
CivetWeb uses the Lua as build in script interpreter. A project that does use Lua and libuv in combination to build a web server is luavit (https://luvit.io/). So, I think the two test candidates would be CivetWeb 1.9 with Lua support (https://github.com/civetweb/civetweb/blob/master/test/page5.lua) in comparison to luavit (https://github.com/luvit/luvit/blob/master/examples/http-server.lua). And the test would be to do 100 concurrent requests to /page5.lua. Actually the luavit example does not care about the uri, and will answer everything with “Hello world\n“ in plain text. CivetWeb will load, interpret and execute the page5.lua script file for every request and will answer with a Hello world HTML page – CivetWeb could do better by using C or pre-compiled Lua scripts, but I did not do any optimization. It will run with –num_threads 100. Both servers run on an older Linux PC, the clients run 100 HTTP/1.0 requests on Windows in one process (in principle this code https://github.com/civetweb/civetweb/blob/master/test/public_server.c#L378, I also tested with curl from the command line, but the measurement is more precise if the client is in C code).
Test 1:
Unmodified code, 10 repetitions of 100 requests,
response time in ms
Luvit: 5875
Civet: 656
Luvit: 6046
Civet: 688
Luvit: 5953
Civet: 484
Luvit: 5828
Civet: 672
Luvit: 5844
Civet: 703
Luvit: 6296
Civet: 688
Luvit: 5812
Civet: 906
Luvit: 5859
Civet: 860
Luvit: 4860
Civet: 734
Luvit: 5797
Civet: 781
Linux memory consumption (https://github.com/pixelb/ps_mem/blob/master/ps_mem.py):
Private + Shared = RAM used
5.5 MiB + 156 kiB = 6.0 MiB civetweb
8.8 MiB + 69.5 kiB = 8.8 MiB luvit
CivetWeb uses more address space (as far as I remember, the Linux default is 8 MB per thread stack, Win32 default is 1 MB), but actually less RAM. Address space does not need RAM, so in contrast to a process, a thread may cost as little as 10kB RAM.
CivetWeb is multithreaded in a single process with a pre-created thread pool.
Same with 10 clients (instead of 100):
Luvit: 562
Civet: 141
Luvit: 515
Civet: 141
Luvit: 782
Civet: 125
Luvit: 625
Civet: 110
Luvit: 485
Civet: 156
Luvit: 578
Civet: 141
Luvit: 547
Civet: 140
Luvit: 515
Civet: 125
Luvit: 500
Civet: 125
Luvit: 500
Civet: 156
Same with 1000 clients (more than CivetWeb threads):
Did neither work with luvit, nor with Civetweb.
Test 2:
Scripts creating “hello world” are rather boring. This time I replaced the “world” in Lua by a function call “GetSomethingFromSomewhere()”. But this function call takes some milliseconds to collect the data from somewhere. In a first test, I just used a sleep 1 to simulate this.
Time for 100 clients in ms:
Luvit: 105250
Civet: 2781
Luvit: 105843
Civet: 2782
Several requests to luvit failed, while Civetweb worked for all 100 clients
Memory consumption for both was about 8.8 MB
Time for 10 clients:
Luvit: 10656
Civet: 1188
Luvit: 10563
Civet: 1187
Luvit: 10500
Civet: 1203
Again, one request to luvit failed
So, one thing you cannot do in this model is use blocking functions in callbacks, since this will scale badly.
The advantage of luvit, on the other hand, if you only have static files (or: no blocking callbacks), you do not need to know how many clients you will have at maximum, while you need some reasonable configuration for CivetWeb. So I tested what will happen if you configure CivetWeb to 100 threads, but use 200 clients.
The clients will be accepted, queued, and processed once a thread is free.
Time for 200 clients:
Luvit: 225250
Civet: 5500
Luvit: 216406
Civet: 5500
Luvit: 213219
Civet: 5406
8 requests (of 600) to CivetWeb failed, and 67 (of 600) to luvit.
Other test scenarios:
A test scenario where luvit might work better than CivetWeb is, if you have to keep a lot of connections open – maybe with websockets. But you probably run into a port limit here earlier.
I will probably do this test some time later.