willb (owner)

Revisions

gist: 82463 Download_button fork
public
Public Clone URL: git://gist.github.com/82463.git
pytest.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <limits.h>
 
#include <Python.h>
 
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);
}