putting my money where my mouth is (re: the novel idea)

Andreas Ericsson ae at op5.se
Mon May 9 17:43:58 CEST 2005


Sorry Sean, but the output is basically just nonsense.

You really need to use a real plugin while doing this test since it's 
quite obvious that calling a function that does nothing is a lot faster 
as an in-core function than as an external program. My experiment showed 
benchmarks between two different ways of executing external programs, so 
it's ok for that to use nonsense data that returns quickly, while yours 
focus on the entire execution cycle from execution-start to 
execution-end. You really need to do something a bit more real to 
investigate the time gained for that (hint, the most time is spent in 
the plugin).

Re-run the test with check_rand.c (you'll find it at 
http://oss.op5.se/nagios). It should compile with the exact same options 
as check_hello, but you'll need to remove the if(argc == 1) conditions 
since that robs it of the random sleep that makes it work as much like a 
real plugin as is humanly possible. Compare it with benchmarks from 
mthread and mplex when running that same plugin and you'll see why 
parallellization is the paramount issue here. The overhead of invoking 
fork(), select(), pthread_create() or popen() doesn't really matter all 
that much.

To save you the trouble of actually running check_rand, I'll tell you 
right now that both mthread and mplex will finish in a maximum of 572 
seconds (give or take one or two), no matter how many threads you run, 
while your testcase (down it to 100 executions) will complete in a 
minimum of below 1 second and a maximum of 57100 seconds (roughly 15 
hours). Actual value should be x * (571 * 0.125) + (x * 6) where x = 
executions, which gives us (roughly) 7750 seconds (2.2 hours) for your 
case. That's with a plugin behaving somewhat properly, but randomly 
taking quite some time to complete. Your program won't have any chance 
to fire up new checks as old ones complete either (err, that's what it 
does, but in a serial manner), while both mthread and mplex can be 
modified only slightly to do just that and thus scales far better.

It would be more useful if the testcase at least did a pthread_create() 
to land on the resolved function and then preferrably a pthread_join() 
to reap the returned value, as this is how an implementation such as 
this would work in practice.

sean finney wrote:
> so, in light of last night's discussion, i decided to throw together
> a small proof of concept to illustrate my point.  attached are three
> files:
> 
> 	- check_hello.c, a simple "plugin" that prints hello world.
> 	- a Makefile that illustrates just how easy it is to build a
> 	  shared object in the way i suggested
> 	- dltest.c, a program that benchmarks one vs. the other by
> 	  executing the system/function calls 1000 times and recording
> 	  elapsed time in microseconds (i'd recommend piping stdout
> 	  to /dev/null)
> 
> this is what i get:
> 
> copelandia[~/nagiosplug/plugtest]09:41:03$ ./dltest >/dev/null
> dlopen: 131
> system: 3698327
> 
> 
> 	sean
> 
> 
> ------------------------------------------------------------------------
> 
> #include <stdio.h>
> 
> int main(){
> 	printf("hello, world!\n");
> }
> 
> 
> ------------------------------------------------------------------------
> 
> dltest:	dltest.c
> 	gcc -g -o dltest dltest.c -ldl
> 
> check_hello.o: check_hello.c
> 	gcc -c check_hello.c
> 
> check_hello.shared.o: check_hello.c
> 	gcc -c -fPIC -Dmain=check_hello check_hello.c
> 
> check_hello: check_hello.o
> 	gcc -o check_hello check_hello.o
> 
> check_hello.so: check_hello.shared.o
> 	ld -shared -o check_hello.so check_hello.o
> 
> test:
> 	./dltest
> 
> 
> ------------------------------------------------------------------------
> 
> #include <stdio.h>
> #include <dlfcn.h>
> #include <sys/time.h>
> #include <time.h>
> 
> const char *ourgv[24] ={ "check_hello", NULL };
> const char *ourcmd = "check_hello";
> extern int optind;
> 
> int main(){
> 	int i;
> 	struct timeval start, midway, end;
> 	long total_func, total_sys;
> 	void *libhandle=NULL; 
> 	int (*check_func)(int, const char**)=NULL;
> 	libhandle=dlopen("./check_hello.so", RTLD_NOW);
> 	if(libhandle==NULL){
> 		fprintf(stderr, "libhandle was null.  damn. %s\n", dlerror());
> 	}
> 	*(void**)(&check_func) =dlsym(libhandle, "check_hello");
> 	if(check_func==NULL || *check_func == NULL){
> 		fprintf(stderr, "check_func was null.  damn. %s\n", dlerror());
> 	}
> 	
> 	gettimeofday(&start, NULL);
> 	for(i=0; i<1000; i++){
> 		system(ourcmd);
> 	}
> 	gettimeofday(&midway, NULL);
> 	for(i=0; i<1000; i++){
> 		(*check_func)(1, ourgv);
> 	}
> 	gettimeofday(&end, NULL);
> 
> 	total_sys = ((midway.tv_sec - start.tv_sec)*1000000) + (midway.tv_usec - start.tv_usec);
> 	total_func = ((end.tv_sec - midway.tv_sec)*1000000) + (end.tv_usec - midway.tv_usec);
> 
> 	fprintf(stderr, "dlopen: %ld\n", total_func);
> 	fprintf(stderr, "system: %ld\n", total_sys);
> }

-- 
Andreas Ericsson                   andreas.ericsson at op5.se
OP5 AB                             www.op5.se
Lead Developer


-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4
opportunities to win big! Highest score wins.NEC IT Guy Games. Play to
win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20




More information about the Developers mailing list