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