From f0b2eb74451c0136fbfd5d3fe54db768510beb5c Mon Sep 17 00:00:00 2001 From: Jockos Date: Thu, 10 Nov 2022 14:03:50 +0100 Subject: [PATCH] feat: improve of performance of PHP variables registration (#94) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: enhance php register variables * apply comments * fix errors * improve benchmark * remove debug statement * use defer * don't use defer in a loop Co-authored-by: Kévin Dunglas --- frankenphp.c | 8 ++++++++ frankenphp.go | 23 +++++++++++++++-------- frankenphp.h | 2 ++ frankenphp_test.go | 23 +++++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index d4ad182..7f3b250 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -474,6 +474,14 @@ static char* frankenphp_read_cookies(void) return ctx->cookie_data; } +void frankenphp_register_bulk_variables(char **variables, size_t size, zval *track_vars_array) +{ + for (size_t i = 0; i < size; i++) + { + if (i%2 == 1) php_register_variable(variables[i-1], variables[i], track_vars_array); + } +} + static void frankenphp_register_variables(zval *track_vars_array) { /* https://www.php.net/manual/en/reserved.variables.server.php */ diff --git a/frankenphp.go b/frankenphp.go index c3031ee..fa56c42 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -444,18 +444,25 @@ func go_register_variables(rh C.uintptr_t, trackVarsArray *C.zval) { r := cgo.Handle(rh).Value().(*http.Request) env = r.Context().Value(contextKey).(*FrankenPHPContext).Env - // FIXME: remove this debug statement - env[fmt.Sprintf("REQUEST_%d", rh)] = "1" + le := len(env) * 2 + cArr := (**C.char)(C.malloc(C.size_t(le) * C.size_t(unsafe.Sizeof((*C.char)(nil))))) + defer C.free(unsafe.Pointer(cArr)) - // TODO: batch this for performance + variables := unsafe.Slice(cArr, le) + + var i int for k, v := range env { - ck := C.CString(k) - cv := C.CString(v) + variables[i] = C.CString(k) + i++ - C.php_register_variable(ck, cv, trackVarsArray) + variables[i] = C.CString(v) + i++ + } - C.free(unsafe.Pointer(ck)) - C.free(unsafe.Pointer(cv)) + C.frankenphp_register_bulk_variables(cArr, C.size_t(le), trackVarsArray) + + for _, v := range variables { + C.free(unsafe.Pointer(v)) } } diff --git a/frankenphp.h b/frankenphp.h index 190f793..a5a8cba 100644 --- a/frankenphp.h +++ b/frankenphp.h @@ -2,6 +2,7 @@ #define _FRANKENPPHP_H #include +#include int frankenphp_check_version(); int frankenphp_init(int num_threads); @@ -26,5 +27,6 @@ uintptr_t frankenphp_clean_server_context(); int frankenphp_request_startup(); int frankenphp_execute_script(const char *file_name); uintptr_t frankenphp_request_shutdown(); +void frankenphp_register_bulk_variables(char **variables, size_t size, zval *track_vars_array); #endif diff --git a/frankenphp_test.go b/frankenphp_test.go index c30d478..0b7a4a7 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -88,6 +88,29 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * wg.Wait() } +func BenchmarkHelloWorld(b *testing.B) { + if err := frankenphp.Init(frankenphp.WithLogger(zap.NewNop())); err != nil { + panic(err) + } + defer frankenphp.Shutdown() + cwd, _ := os.Getwd() + testDataDir := cwd + "/testdata/" + + handler := func(w http.ResponseWriter, r *http.Request) { + req := frankenphp.NewRequestWithContext(r, testDataDir, nil) + if err := frankenphp.ServeHTTP(w, req); err != nil { + panic(err) + } + } + + req := httptest.NewRequest("GET", "http://example.com/index.php", nil) + w := httptest.NewRecorder() + + for i := 0; i < b.N; i++ { + handler(w, req) + } +} + func TestHelloWorld_module(t *testing.T) { testHelloWorld(t, nil) } func TestHelloWorld_worker(t *testing.T) { testHelloWorld(t, &testOptions{workerScript: "index.php"}) } func testHelloWorld(t *testing.T, opts *testOptions) {