/* Simple timing test of exec-ing versus embedding python interpreter. Note that to embed python programs with dynamically loaded extension modules, you'll need to do some special linking tricks: http://www.python.org/doc/2.5.2/ext/link-reqs.html Compile this file with something like: gcc pytest.c -I/usr/include/python2.5 -L/usr/lib64/python2.5 -lpython2.5 -o pytest And then run like this (be sure to redirect stdout to the bit bucket): ./pytest 10000 > /dev/null */ #include #include #include #include #include #include #include const char* noop_program = "import sys; print 'foo'; sys.exit(0)\n"; const char* noop_program_noexit = "import sys; print 'foo'\n"; const char* noop_program_name = "noop_program_XXXXXX"; /* This test just checks to see how quickly we can fork a child process and wait for that child to exit */ void forkTest(int times, int do_wait) { int i; for (i = 0; i < times; i++) { if (fork()) { if (do_wait) { wait(NULL); } } else { exit(0); } } } /* This test repeatedly forks and execs the python interpreter in order to run a trivial program. */ void execPythonInterpreter(int times, int do_wait) { int i; char *scriptname = strdup(noop_program_name); int fd = mkstemp(scriptname); write(fd, noop_program, strlen(noop_program)); fsync(fd); close(fd); for (i = 0; i < times; i++) { if (fork()) { if (do_wait) { wait(NULL); } } else { execlp("python", "-c", scriptname, NULL); exit(0); } } } /* This test repeatedly forks child processes that run the embedded python interpreter */ void runEmbeddedInterpreter(int times, int do_wait) { int i; Py_Initialize(); for (i = 0; i < times; i++) { if (fork()) { if (do_wait) { wait(NULL); } } else { PyRun_SimpleString(noop_program); } } Py_Finalize(); } /* This test repeatedly runs the embedded python interpreter (NB: the script cannot exit or else the test will terminate! */ void runEmbeddedInterpreterNoFork(int times, int do_wait) { int i; Py_Initialize(); for (i = 0; i < times; i++) { PyRun_SimpleString(noop_program_noexit); } Py_Finalize(); } double tv2sec(struct timeval *tv) { return (tv->tv_sec) + ((double)(tv->tv_usec) / 1000000); } typedef void (*trial_t)(int, int); void try_and_report(trial_t t, const char* name, int reps) { struct timeval before, after; double duration; gettimeofday(&before, NULL); t(reps, 1); gettimeofday(&after, NULL); duration = (tv2sec(&after) - tv2sec(&before)); fprintf(stderr, "%12s: %d reps in %g sec; %g reps/sec\n", name, reps, duration, reps/duration); } int main(int c, char *v[]) { int reps = 1000; if (c > 1) { long ureps = strtol(v[1], NULL, 10); if(ureps > 0 && ureps < INT_MAX) { reps = (int)ureps; } } try_and_report(forkTest, "fork-only", reps); try_and_report(execPythonInterpreter, "exec-python", reps); try_and_report(runEmbeddedInterpreter, "embed", reps); try_and_report(runEmbeddedInterpreterNoFork, "emb/nofork", reps); exit(0); }