feat: improve of performance of PHP variables registration (#94)

* 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 <kevin@dunglas.fr>
This commit is contained in:
Jockos 2022-11-10 14:03:50 +01:00 committed by GitHub
parent 3abda4fbb6
commit f0b2eb7445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 8 deletions

View File

@ -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 */

View File

@ -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))
}
}

View File

@ -2,6 +2,7 @@
#define _FRANKENPPHP_H
#include <stdint.h>
#include <Zend/zend_types.h>
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

View File

@ -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) {