Skip to content

Commit 75e735a

Browse files
authored
H2O: Optimize the implementation further (#2356)
2 parents 1008d96 + b25a29a commit 75e735a

16 files changed

+253
-196
lines changed

frameworks/C/h2o/setup.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ run_curl()
2525

2626
run_h2o_app()
2727
{
28-
"$1/h2o_app" -a2 -f "$2/template/fortunes.mustache" -m8 "$3" "$4" \
28+
"$1/h2o_app" -a1 -f "$2/template/fortunes.mustache" -m5 "$3" "$4" \
2929
-d "host=$DBHOST dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass" &
3030
}
3131

frameworks/C/h2o/src/database.c

+4-5
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,7 @@ static void start_database_connect(thread_context_t *ctx, db_conn_t *db_conn)
353353
goto error;
354354
}
355355

356-
const char * const conninfo =
357-
ctx->global_data->config->db_host ? ctx->global_data->config->db_host : "";
356+
const char * const conninfo = ctx->config->db_host ? ctx->config->db_host : "";
358357

359358
db_conn->conn = PQconnectStart(conninfo);
360359

@@ -441,7 +440,7 @@ static void stop_database_write_polling(db_conn_t *db_conn)
441440

442441
void connect_to_database(thread_context_t *ctx)
443442
{
444-
for (size_t i = ctx->db_state.db_conn_num; i < ctx->global_data->config->max_db_conn_num; i++)
443+
for (size_t i = ctx->db_state.db_conn_num; i < ctx->config->max_db_conn_num; i++)
445444
start_database_connect(ctx, NULL);
446445
}
447446

@@ -475,13 +474,13 @@ int execute_query(thread_context_t *ctx, db_query_param_t *param)
475474
db_conn->param = param;
476475
do_execute_query(db_conn);
477476
}
478-
else if (ctx->db_state.query_num < ctx->global_data->config->max_query_num) {
477+
else if (ctx->db_state.query_num < ctx->config->max_query_num) {
479478
param->l.next = NULL;
480479
*ctx->db_state.queries.tail = &param->l;
481480
ctx->db_state.queries.tail = &param->l.next;
482481
ctx->db_state.query_num++;
483482

484-
if (ctx->db_state.db_conn_num < ctx->global_data->config->max_db_conn_num)
483+
if (ctx->db_state.db_conn_num < ctx->config->max_db_conn_num)
485484
start_database_connect(ctx, NULL);
486485
}
487486
else

frameworks/C/h2o/src/event_loop.c

+11-14
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <string.h>
2525
#include <unistd.h>
2626
#include <sys/epoll.h>
27-
#include <sys/syscall.h>
2827

2928
#include "error.h"
3029
#include "event_loop.h"
@@ -57,7 +56,7 @@ static void accept_connection(h2o_socket_t *listener, const char *err)
5756
sock->on_close.cb = on_close_connection;
5857
sock->on_close.data = &ctx->event_loop.conn_num;
5958
h2o_accept(&ctx->event_loop.h2o_accept_ctx, sock);
60-
} while (++accepted < ctx->global_data->config->max_accept);
59+
} while (++accepted < ctx->config->max_accept);
6160
}
6261
}
6362
}
@@ -96,11 +95,11 @@ static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_
9695
{
9796
IGNORE_FUNCTION_PARAMETER(messages);
9897

99-
thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
100-
event_loop.h2o_receiver,
101-
receiver);
98+
global_thread_data_t * const global_thread_data = H2O_STRUCT_FROM_MEMBER(global_thread_data_t,
99+
h2o_receiver,
100+
receiver);
102101

103-
h2o_socket_read_stop(ctx->event_loop.h2o_socket);
102+
h2o_socket_read_stop(global_thread_data->ctx->event_loop.h2o_socket);
104103
}
105104

106105
static void shutdown_server(h2o_socket_t *listener, const char *err)
@@ -113,30 +112,28 @@ static void shutdown_server(h2o_socket_t *listener, const char *err)
113112
ctx->global_data->shutdown = true;
114113
h2o_socket_read_stop(ctx->event_loop.h2o_socket);
115114

116-
for (size_t i = 1; i < ctx->global_data->config->thread_num; i++)
117-
h2o_multithread_send_message(&ctx[i].event_loop.h2o_receiver, NULL);
115+
for (size_t i = 1; i < ctx->config->thread_num; i++)
116+
h2o_multithread_send_message(&ctx->global_thread_data[i].h2o_receiver, NULL);
118117
}
119118
}
120119

121120
void event_loop(thread_context_t *ctx)
122121
{
123-
ctx->tid = syscall(SYS_gettid);
124-
ctx->random_seed = ctx->tid;
125-
126122
while (!ctx->global_data->shutdown || ctx->event_loop.conn_num)
127123
h2o_evloop_run(ctx->event_loop.h2o_ctx.loop);
128124
}
129125

130-
void free_event_loop(event_loop_t *event_loop)
126+
void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver)
131127
{
132-
h2o_multithread_unregister_receiver(event_loop->h2o_ctx.queue, &event_loop->h2o_receiver);
128+
h2o_multithread_unregister_receiver(event_loop->h2o_ctx.queue, h2o_receiver);
133129
h2o_socket_close(event_loop->h2o_socket);
134130
h2o_socket_close(event_loop->epoll_socket);
135131
h2o_context_dispose(&event_loop->h2o_ctx);
136132
}
137133

138134
void initialize_event_loop(bool is_main_thread,
139135
global_data_t *global_data,
136+
h2o_multithread_receiver_t *h2o_receiver,
140137
event_loop_t *loop)
141138
{
142139
memset(loop, 0, sizeof(*loop));
@@ -165,7 +162,7 @@ void initialize_event_loop(bool is_main_thread,
165162
loop->h2o_socket->data = loop;
166163
h2o_socket_read_start(loop->h2o_socket, accept_connection);
167164
h2o_multithread_register_receiver(loop->h2o_ctx.queue,
168-
&loop->h2o_receiver,
165+
h2o_receiver,
169166
process_messages);
170167
// libh2o's event loop does not support write polling unless it
171168
// controls sending the data as well, so do read polling on the

frameworks/C/h2o/src/event_loop.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ typedef struct {
3535
int epoll_fd;
3636
h2o_accept_ctx_t h2o_accept_ctx;
3737
h2o_context_t h2o_ctx;
38-
h2o_multithread_receiver_t h2o_receiver;
3938
} event_loop_t;
4039

4140
void event_loop(thread_context_t *ctx);
42-
void free_event_loop(event_loop_t *event_loop);
41+
void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver);
4342
void initialize_event_loop(bool is_main_thread,
4443
global_data_t *global_data,
44+
h2o_multithread_receiver_t *h2o_receiver,
4545
event_loop_t *loop);
4646
int start_write_polling(int fd,
4747
void (**on_write_ready)(void *),

frameworks/C/h2o/src/fortune.c

+37-28
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ static uintmax_t add_iovec(mustache_api_t *api,
5959
void *userdata,
6060
const char *buffer,
6161
uintmax_t buffer_size);
62+
static void cleanup_fortunes(void *data);
6263
static int compare_fortunes(const list_t *x, const list_t *y);
6364
static void complete_fortunes(struct st_h2o_generator_t *self, h2o_req_t *req);
6465
static list_t *get_sorted_sublist(list_t *head);
@@ -109,6 +110,22 @@ static uintmax_t add_iovec(mustache_api_t *api,
109110
return ret;
110111
}
111112

113+
static void cleanup_fortunes(void *data)
114+
{
115+
fortune_ctx_t * const fortune_ctx = data;
116+
const list_t *iter = fortune_ctx->result;
117+
118+
if (iter)
119+
do {
120+
const fortune_t * const fortune = H2O_STRUCT_FROM_MEMBER(fortune_t, l, iter);
121+
122+
if (fortune->data)
123+
PQclear(fortune->data);
124+
125+
iter = iter->next;
126+
} while (iter);
127+
}
128+
112129
static int compare_fortunes(const list_t *x, const list_t *y)
113130
{
114131
const fortune_t * const f1 = H2O_STRUCT_FROM_MEMBER(fortune_t, l, x);
@@ -142,12 +159,7 @@ static list_t *get_sorted_sublist(list_t *head)
142159
if (head) {
143160
head = head->next;
144161

145-
while (head && compare_fortunes(tail, head) < 0) {
146-
tail = head;
147-
head = head->next;
148-
}
149-
150-
while (head && !compare_fortunes(tail, head)) {
162+
while (head && compare_fortunes(tail, head) <= 0) {
151163
tail = head;
152164
head = head->next;
153165
}
@@ -209,40 +221,33 @@ static result_return_t on_fortune_result(db_query_param_t *param, PGresult *resu
209221
ret = SUCCESS;
210222

211223
for (size_t i = 0; i < num_rows; i++) {
212-
const char * const message_data = PQgetvalue(result, i, 1);
213-
h2o_iovec_t message = h2o_htmlescape(&fortune_ctx->req->pool,
214-
message_data,
215-
PQgetlength(result, i, 1));
216-
const size_t id_len = PQgetlength(result, i, 0);
217-
const size_t fortune_size = offsetof(fortune_t, data) + id_len +
218-
(message_data == message.base ? message.len : 0);
219224
fortune_t * const fortune = h2o_mem_alloc_pool(&fortune_ctx->req->pool,
220-
fortune_size);
225+
sizeof(*fortune));
221226

222227
if (fortune) {
223-
memset(fortune, 0, offsetof(fortune_t, data));
224-
memcpy(fortune->data, PQgetvalue(result, i, 0), id_len);
225-
fortune->id.base = fortune->data;
226-
fortune->id.len = id_len;
227-
228-
if (message_data == message.base) {
229-
message.base = fortune->data + id_len;
230-
memcpy(message.base, message_data, message.len);
231-
}
232-
233-
fortune->message = message;
228+
memset(fortune, 0, sizeof(*fortune));
229+
fortune->id.base = PQgetvalue(result, i, 0);
230+
fortune->id.len = PQgetlength(result, i, 0);
231+
fortune->message = h2o_htmlescape(&fortune_ctx->req->pool,
232+
PQgetvalue(result, i, 1),
233+
PQgetlength(result, i, 1));
234234
fortune->l.next = fortune_ctx->result;
235235
fortune_ctx->result = &fortune->l;
236236
fortune_ctx->num_result++;
237+
238+
if (!i)
239+
fortune->data = result;
237240
}
238241
else {
239242
send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, fortune_ctx->req);
240243
ret = DONE;
244+
245+
if (!i)
246+
PQclear(result);
247+
241248
break;
242249
}
243250
}
244-
245-
PQclear(result);
246251
}
247252
else if (result) {
248253
PQclear(result);
@@ -365,7 +370,9 @@ int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
365370
thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t,
366371
event_loop.h2o_ctx,
367372
req->conn->ctx);
368-
fortune_ctx_t * const fortune_ctx = h2o_mem_alloc_pool(&req->pool, sizeof(*fortune_ctx));
373+
fortune_ctx_t * const fortune_ctx = h2o_mem_alloc_shared(&req->pool,
374+
sizeof(*fortune_ctx),
375+
cleanup_fortunes);
369376

370377
if (fortune_ctx) {
371378
fortune_t * const fortune = h2o_mem_alloc_pool(&req->pool, sizeof(*fortune));
@@ -390,6 +397,8 @@ int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req)
390397
if (execute_query(ctx, &fortune_ctx->param))
391398
send_service_unavailable_error(DB_REQ_ERROR, req);
392399
}
400+
else
401+
send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);
393402
}
394403
else
395404
send_error(INTERNAL_SERVER_ERROR, MEM_ALLOC_ERR_MSG, req);

frameworks/C/h2o/src/fortune.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828

2929
typedef struct {
3030
list_t l;
31+
PGresult *data;
3132
h2o_iovec_t id;
3233
h2o_iovec_t message;
33-
char data[];
3434
} fortune_t;
3535

3636
int fortunes(struct st_h2o_handler_t *self, h2o_req_t *req);

frameworks/C/h2o/src/main.c

+25-10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <netdb.h>
2525
#include <signal.h>
2626
#include <stdarg.h>
27+
#include <stdbool.h>
2728
#include <stdio.h>
2829
#include <stdlib.h>
2930
#include <string.h>
@@ -44,6 +45,7 @@
4445
#include "tls.h"
4546
#include "utility.h"
4647

48+
#define DEFAULT_CACHE_LINE_SIZE 128
4749
#define DEFAULT_TCP_FASTOPEN_QUEUE_LEN 4096
4850
#define USAGE_MESSAGE \
4951
"Usage:\n%s [-a <max connections accepted simultaneously>] [-b <bind address>] " \
@@ -63,8 +65,12 @@ static void setup_process(void);
6365

6466
static void free_global_data(global_data_t *global_data)
6567
{
66-
if (global_data->ctx)
67-
free_thread_contexts(global_data);
68+
if (global_data->global_thread_data) {
69+
for (size_t i = 1; i < global_data->global_thread_data->config->thread_num; i++)
70+
CHECK_ERROR(pthread_join, global_data->global_thread_data[i].thread, NULL);
71+
72+
free(global_data->global_thread_data);
73+
}
6874

6975
if (global_data->file_logger)
7076
global_data->file_logger->dispose(global_data->file_logger);
@@ -177,9 +183,7 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
177183
sigset_t signals;
178184

179185
memset(global_data, 0, sizeof(*global_data));
180-
global_data->config = config;
181186
global_data->memory_alignment = get_maximum_cache_line_size();
182-
assert(global_data->memory_alignment <= DEFAULT_CACHE_LINE_SIZE);
183187
CHECK_ERRNO(sigemptyset, &signals);
184188
#ifdef NDEBUG
185189
CHECK_ERRNO(sigaddset, &signals, SIGINT);
@@ -194,7 +198,7 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
194198
goto error;
195199

196200
if (config->cert && config->key)
197-
initialize_openssl(global_data);
201+
initialize_openssl(config, global_data);
198202

199203
const h2o_iovec_t host = h2o_iovec_init(H2O_STRLIT("default"));
200204
h2o_hostconf_t * const hostconf = h2o_config_register_host(&global_data->h2o_config,
@@ -220,10 +224,14 @@ static int initialize_global_data(const config_t *config, global_data_t *global_
220224
global_data->file_logger = h2o_access_log_register(pathconf, log_handle);
221225
}
222226

223-
global_data->ctx = initialize_thread_contexts(global_data);
227+
global_data->global_thread_data = initialize_global_thread_data(config, global_data);
224228

225-
if (global_data->ctx)
229+
if (global_data->global_thread_data) {
230+
printf("Number of processors: %zu\nMaximum cache line size: %zu\n",
231+
h2o_numproc(),
232+
global_data->memory_alignment);
226233
return EXIT_SUCCESS;
234+
}
227235

228236
error:
229237
free_global_data(global_data);
@@ -353,10 +361,17 @@ int main(int argc, char *argv[])
353361
global_data_t global_data;
354362

355363
if (initialize_global_data(&config, &global_data) == EXIT_SUCCESS) {
364+
thread_context_t ctx;
365+
356366
setup_process();
357-
start_threads(global_data.ctx);
358-
connect_to_database(global_data.ctx);
359-
event_loop(global_data.ctx);
367+
start_threads(global_data.global_thread_data);
368+
initialize_thread_context(global_data.global_thread_data, true, &ctx);
369+
connect_to_database(&ctx);
370+
event_loop(&ctx);
371+
// Even though this is global data, we need to close
372+
// it before the associated event loop is cleaned up.
373+
h2o_socket_close(global_data.signals);
374+
free_thread_context(&ctx);
360375
free_global_data(&global_data);
361376
rc = EXIT_SUCCESS;
362377
}

0 commit comments

Comments
 (0)