xref: /libuv/test/benchmark-spawn.c (revision 011a1ac1)
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 /* This benchmark spawns itself 1000 times. */
23 
24 #include "task.h"
25 #include "uv.h"
26 
27 static uv_loop_t* loop;
28 
29 static int N = 1000;
30 static int done;
31 
32 static uv_process_t process;
33 static uv_process_options_t options;
34 static char exepath[1024];
35 static size_t exepath_size = 1024;
36 static char* args[3];
37 static uv_pipe_t out;
38 
39 #define OUTPUT_SIZE 1024
40 static char output[OUTPUT_SIZE];
41 static int output_used;
42 
43 static int process_open;
44 static int pipe_open;
45 
46 
47 static void spawn(void);
48 
49 
maybe_spawn(void)50 static void maybe_spawn(void) {
51   if (process_open == 0 && pipe_open == 0) {
52     done++;
53     if (done < N) {
54       spawn();
55     }
56   }
57 }
58 
59 
process_close_cb(uv_handle_t * handle)60 static void process_close_cb(uv_handle_t* handle) {
61   ASSERT_EQ(1, process_open);
62   process_open = 0;
63   maybe_spawn();
64 }
65 
66 
exit_cb(uv_process_t * process,int64_t exit_status,int term_signal)67 static void exit_cb(uv_process_t* process,
68                     int64_t exit_status,
69                     int term_signal) {
70   ASSERT_EQ(42, exit_status);
71   ASSERT_OK(term_signal);
72   uv_close((uv_handle_t*)process, process_close_cb);
73 }
74 
75 
on_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)76 static void on_alloc(uv_handle_t* handle,
77                      size_t suggested_size,
78                      uv_buf_t* buf) {
79   buf->base = output + output_used;
80   buf->len = OUTPUT_SIZE - output_used;
81 }
82 
83 
pipe_close_cb(uv_handle_t * pipe)84 static void pipe_close_cb(uv_handle_t* pipe) {
85   ASSERT_EQ(1, pipe_open);
86   pipe_open = 0;
87   maybe_spawn();
88 }
89 
90 
on_read(uv_stream_t * pipe,ssize_t nread,const uv_buf_t * buf)91 static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
92   if (nread > 0) {
93     ASSERT_EQ(1, pipe_open);
94     output_used += nread;
95   } else if (nread < 0) {
96     if (nread == UV_EOF) {
97       uv_close((uv_handle_t*)pipe, pipe_close_cb);
98     }
99   }
100 }
101 
102 
spawn(void)103 static void spawn(void) {
104   uv_stdio_container_t stdio[2];
105   int r;
106 
107   ASSERT_OK(process_open);
108   ASSERT_OK(pipe_open);
109 
110   args[0] = exepath;
111   args[1] = "spawn_helper";
112   args[2] = NULL;
113   options.file = exepath;
114   options.args = args;
115   options.exit_cb = exit_cb;
116 
117   uv_pipe_init(loop, &out, 0);
118 
119   options.stdio = stdio;
120   options.stdio_count = 2;
121   options.stdio[0].flags = UV_IGNORE;
122   options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
123   options.stdio[1].data.stream = (uv_stream_t*)&out;
124 
125   r = uv_spawn(loop, &process, &options);
126   ASSERT_OK(r);
127 
128   process_open = 1;
129   pipe_open = 1;
130   output_used = 0;
131 
132   r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
133   ASSERT_OK(r);
134 }
135 
136 
BENCHMARK_IMPL(spawn)137 BENCHMARK_IMPL(spawn) {
138   int r;
139   static int64_t start_time, end_time;
140 
141   loop = uv_default_loop();
142 
143   r = uv_exepath(exepath, &exepath_size);
144   ASSERT_OK(r);
145   exepath[exepath_size] = '\0';
146 
147   uv_update_time(loop);
148   start_time = uv_now(loop);
149 
150   spawn();
151 
152   r = uv_run(loop, UV_RUN_DEFAULT);
153   ASSERT_OK(r);
154 
155   uv_update_time(loop);
156   end_time = uv_now(loop);
157 
158   fprintf(stderr, "spawn: %.0f spawns/s\n",
159           (double) N / (double) (end_time - start_time) * 1000.0);
160   fflush(stderr);
161 
162   MAKE_VALGRIND_HAPPY(loop);
163   return 0;
164 }
165