Skip to content

Commit f43fe06

Browse files
committed
Avoid hash value recalculation on each counter update
1 parent 8aff662 commit f43fe06

File tree

4 files changed

+63
-147
lines changed

4 files changed

+63
-147
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2693,18 +2693,19 @@ void zend_jit_check_funcs(HashTable *function_table, zend_bool is_method) {
26932693
void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
26942694
{
26952695
zend_op_array *op_array = &EX(func)->op_array;
2696-
const void **orig_handlers;
2696+
zend_jit_op_array_extension *jit_extension;
26972697
uint32_t i;
26982698

26992699
zend_shared_alloc_lock();
2700-
orig_handlers = (const void**)ZEND_FUNC_INFO(op_array);
2700+
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
27012701

2702-
if (orig_handlers) {
2702+
if (jit_extension) {
27032703
SHM_UNPROTECT();
27042704
zend_jit_unprotect();
27052705

2706+
*(jit_extension->counter) = ZEND_JIT_HOT_COUNTER_INIT;
27062707
for (i = 0; i < op_array->last; i++) {
2707-
op_array->opcodes[i].handler = orig_handlers[i];
2708+
op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
27082709
}
27092710
ZEND_SET_FUNC_INFO(op_array, NULL);
27102711

@@ -2723,19 +2724,20 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
27232724
static int zend_jit_setup_hot_counters(zend_op_array *op_array)
27242725
{
27252726
zend_op *opline = op_array->opcodes;
2726-
const void **orig_handlers;
2727+
zend_jit_op_array_extension *jit_extension;
27272728
zend_cfg cfg;
27282729
uint32_t i;
27292730

27302731
if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
27312732
return FAILURE;
27322733
}
27332734

2734-
orig_handlers = (const void**)zend_shared_alloc(op_array->last * sizeof(void*));
2735+
jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension) + (op_array->last - 1) * sizeof(void*));
2736+
jit_extension->counter = &zend_jit_hot_counters[zend_jit_op_array_hash(op_array) & (ZEND_HOT_COUNTERS_COUNT - 1)];
27352737
for (i = 0; i < op_array->last; i++) {
2736-
orig_handlers[i] = op_array->opcodes[i].handler;
2738+
jit_extension->orig_handlers[i] = op_array->opcodes[i].handler;
27372739
}
2738-
ZEND_SET_FUNC_INFO(op_array, (void*)orig_handlers);
2740+
ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
27392741

27402742
while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
27412743
opline++;

ext/opcache/jit/zend_jit_internal.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,35 @@ extern int zend_jit_profile_counter_rid;
2828
ZEND_OP_ARRAY_EXTENSION(op_array, zend_jit_profile_counter_rid)
2929

3030
/* Hot Counters */
31+
3132
#define ZEND_HOT_COUNTERS_COUNT 128
3233

3334
extern int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
3435

3536
void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline);
3637

38+
typedef struct _zend_jit_op_array_extension {
39+
int16_t *counter;
40+
const void *orig_handlers[1];
41+
} zend_jit_op_array_extension;
42+
43+
static zend_always_inline zend_long zend_jit_op_array_hash(const zend_op_array *op_array)
44+
{
45+
uintptr_t x;
46+
47+
x = (uintptr_t)op_array->opcodes >> 3;
48+
#if SIZEOF_SIZE_T == 4
49+
x = ((x >> 16) ^ x) * 0x45d9f3b;
50+
x = ((x >> 16) ^ x) * 0x45d9f3b;
51+
x = (x >> 16) ^ x;
52+
#elif SIZEOF_SIZE_T == 8
53+
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
54+
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
55+
x = x ^ (x >> 31);
56+
#endif
57+
return x;
58+
}
59+
3760
extern const zend_op *zend_jit_halt_op;
3861

3962
#ifdef HAVE_GCC_GLOBAL_REGS

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -182,67 +182,40 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLE
182182
ZEND_OPCODE_TAIL_CALL(handler);
183183
}
184184

185-
static zend_always_inline zend_long _op_array_hash(const zend_op_array *op_array)
186-
{
187-
uintptr_t x;
188-
189-
if (op_array->function_name) {
190-
x = (uintptr_t)op_array >> 3;
191-
} else {
192-
x = (uintptr_t)op_array->filename >> 3;
193-
}
194-
#if SIZEOF_SIZE_T == 4
195-
x = ((x >> 16) ^ x) * 0x45d9f3b;
196-
x = ((x >> 16) ^ x) * 0x45d9f3b;
197-
x = (x >> 16) ^ x;
198-
#elif SIZEOF_SIZE_T == 8
199-
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
200-
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
201-
x = x ^ (x >> 31);
202-
#endif
203-
return x;
204-
}
205-
206185
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
207186
{
187+
zend_jit_op_array_extension *jit_extension =
188+
(zend_jit_op_array_extension*)ZEND_FUNC_INFO(&EX(func)->op_array);
208189
#ifndef HAVE_GCC_GLOBAL_REGS
209190
const zend_op *opline = EX(opline);
210191
#endif
211-
unsigned int n = _op_array_hash(&EX(func)->op_array) %
212-
(sizeof(zend_jit_hot_counters) / sizeof(zend_jit_hot_counters[0]));
213192

214-
zend_jit_hot_counters[n] -= ZEND_JIT_HOT_FUNC_COST;
193+
*(jit_extension->counter) -= ZEND_JIT_HOT_FUNC_COST;
215194

216-
if (UNEXPECTED(zend_jit_hot_counters[n] <= 0)) {
217-
zend_jit_hot_counters[n] = ZEND_JIT_HOT_COUNTER_INIT;
195+
if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
218196
zend_jit_hot_func(execute_data, opline);
219197
ZEND_OPCODE_RETURN();
220198
} else {
221-
zend_vm_opcode_handler_t *handlers =
222-
(zend_vm_opcode_handler_t*)ZEND_FUNC_INFO(&EX(func)->op_array);
223-
zend_vm_opcode_handler_t handler = handlers[opline - EX(func)->op_array.opcodes];
199+
zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
224200
ZEND_OPCODE_TAIL_CALL(handler);
225201
}
226202
}
227203

228204
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
229205
{
206+
zend_jit_op_array_extension *jit_extension =
207+
(zend_jit_op_array_extension*)ZEND_FUNC_INFO(&EX(func)->op_array);
230208
#ifndef HAVE_GCC_GLOBAL_REGS
231209
const zend_op *opline = EX(opline);
232210
#endif
233-
unsigned int n = _op_array_hash(&EX(func)->op_array) %
234-
(sizeof(zend_jit_hot_counters) / sizeof(zend_jit_hot_counters[0]));
235211

236-
zend_jit_hot_counters[n] -= ZEND_JIT_HOT_LOOP_COST;
212+
*(jit_extension->counter) -= ZEND_JIT_HOT_LOOP_COST;
237213

238-
if (UNEXPECTED(zend_jit_hot_counters[n] <= 0)) {
239-
zend_jit_hot_counters[n] = ZEND_JIT_HOT_COUNTER_INIT;
214+
if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
240215
zend_jit_hot_func(execute_data, opline);
241216
ZEND_OPCODE_RETURN();
242217
} else {
243-
zend_vm_opcode_handler_t *handlers =
244-
(zend_vm_opcode_handler_t*)ZEND_FUNC_INFO(&EX(func)->op_array);
245-
zend_vm_opcode_handler_t handler = handlers[opline - EX(func)->op_array.opcodes];
218+
zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
246219
ZEND_OPCODE_TAIL_CALL(handler);
247220
}
248221
}

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 20 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,68 +2176,27 @@ static int zend_jit_hybrid_func_counter_stub(dasm_State **Dst)
21762176
{
21772177
|->hybrid_func_counter:
21782178
| mov r0, EX->func
2179-
| mov r1, aword [r0 + offsetof(zend_op_array, function_name)]
2180-
| test r1, r1
2181-
| jne >1
2182-
| mov r0, aword [r0 + offsetof(zend_op_array, filename)]
2183-
|1:
2184-
| shr r0, 3
2185-
| mov r1, r0
2186-
| .if X64
2187-
| shr r0, 30
2188-
| xor r0, r1
2189-
| mov64 r1, 0xbf58476d1ce4e5b9
2190-
| imul r0, r1
2191-
| mov r1, r0
2192-
| shr r0, 27
2193-
| xor r0, r1
2194-
| mov64 r1, 0x94d049bb133111eb
2195-
| imul r0, r1
2196-
| mov r1, r0
2197-
| shr r0, 31
2198-
| xor r1, r0
2199-
| and r1, ZEND_HOT_COUNTERS_COUNT-1
2200-
| LOAD_ADDR r0, &zend_jit_hot_counters
2201-
| sub word [r0+r1*2], ZEND_JIT_HOT_FUNC_COST
2202-
| .else
2203-
| shr r0, 16
2204-
| xor r0, r1
2205-
| imul r0, 0x45d9f3b
2206-
| mov r1, r0
2207-
| shr r0, 16
2208-
| xor r0, r1
2209-
| imul r0, 0x45d9f3b
2210-
| mov r1, r0
2211-
| shr r0, 16
2212-
| xor r1, r0
2213-
| and r1, ZEND_HOT_COUNTERS_COUNT-1
2214-
| sub word [r1*2+&zend_jit_hot_counters], ZEND_JIT_HOT_FUNC_COST
2215-
| .endif
2179+
| mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2180+
| mov r2, aword [r1]
2181+
| sub word [r2], ZEND_JIT_HOT_FUNC_COST
22162182
| jle >1
2217-
| mov r1, EX->func
2218-
| GET_IP r0
2219-
| sub r0, aword [r1 + offsetof(zend_op_array, opcodes)]
2183+
| GET_IP r2
2184+
| sub r2, aword [r0 + offsetof(zend_op_array, opcodes)]
22202185
| // divide by sizeof(zend_op)
22212186
| .if X64
22222187
|| ZEND_ASSERT(sizeof(zend_op) == 32);
2223-
| sar r0, 5
2188+
| sar r2, 5
22242189
| .else
22252190
|| ZEND_ASSERT(sizeof(zend_op) == 28);
2226-
| sar r0, 2
2227-
| imul r0, 0xb6db6db7
2191+
| sar r2, 2
2192+
| imul r2, 0xb6db6db7
22282193
| .endif
2229-
| mov r1, aword [r1 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
22302194
| .if X64
2231-
| jmp aword [r1+r0*8]
2195+
| jmp aword [r1+r2*8+8]
22322196
| .else
2233-
| jmp aword [r1+r0*4]
2197+
| jmp aword [r1+r2*4+4]
22342198
| .endif
22352199
|1:
2236-
| .if X64
2237-
| mov word [r0+r1*2], ZEND_JIT_HOT_COUNTER_INIT
2238-
| .else
2239-
| mov word [r1*2+&zend_jit_hot_counters], ZEND_JIT_HOT_COUNTER_INIT
2240-
| .endif
22412200
| mov FCARG1a, FP
22422201
| GET_IP FCARG2a
22432202
| EXT_CALL zend_jit_hot_func, r0
@@ -2249,68 +2208,27 @@ static int zend_jit_hybrid_loop_counter_stub(dasm_State **Dst)
22492208
{
22502209
|->hybrid_loop_counter:
22512210
| mov r0, EX->func
2252-
| mov r1, aword [r0 + offsetof(zend_op_array, function_name)]
2253-
| test r1, r1
2254-
| jne >1
2255-
| mov r0, aword [r0 + offsetof(zend_op_array, filename)]
2256-
|1:
2257-
| shr r0, 3
2258-
| mov r1, r0
2259-
| .if X64
2260-
| shr r0, 30
2261-
| xor r0, r1
2262-
| mov64 r1, 0xbf58476d1ce4e5b9
2263-
| imul r0, r1
2264-
| mov r1, r0
2265-
| shr r0, 27
2266-
| xor r0, r1
2267-
| mov64 r1, 0x94d049bb133111eb
2268-
| imul r0, r1
2269-
| mov r1, r0
2270-
| shr r0, 31
2271-
| xor r1, r0
2272-
| and r1, ZEND_HOT_COUNTERS_COUNT-1
2273-
| LOAD_ADDR r0, &zend_jit_hot_counters
2274-
| sub word [r0+r1*2], ZEND_JIT_HOT_LOOP_COST
2275-
| .else
2276-
| shr r0, 16
2277-
| xor r0, r1
2278-
| imul r0, 0x45d9f3b
2279-
| mov r1, r0
2280-
| shr r0, 16
2281-
| xor r0, r1
2282-
| imul r0, 0x45d9f3b
2283-
| mov r1, r0
2284-
| shr r0, 16
2285-
| xor r1, r0
2286-
| and r1, ZEND_HOT_COUNTERS_COUNT-1
2287-
| sub word [r1*2+&zend_jit_hot_counters], ZEND_JIT_HOT_LOOP_COST
2288-
| .endif
2211+
| mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2212+
| mov r2, aword [r1]
2213+
| sub word [r2], ZEND_JIT_HOT_LOOP_COST
22892214
| jle >1
2290-
| mov r1, EX->func
2291-
| GET_IP r0
2292-
| sub r0, aword [r1 + offsetof(zend_op_array, opcodes)]
2215+
| GET_IP r2
2216+
| sub r2, aword [r0 + offsetof(zend_op_array, opcodes)]
22932217
| // divide by sizeof(zend_op)
22942218
| .if X64
22952219
|| ZEND_ASSERT(sizeof(zend_op) == 32);
2296-
| sar r0, 5
2220+
| sar r2, 5
22972221
| .else
22982222
|| ZEND_ASSERT(sizeof(zend_op) == 28);
2299-
| sar r0, 2
2300-
| imul r0, 0xb6db6db7
2223+
| sar r2, 2
2224+
| imul r2, 0xb6db6db7
23012225
| .endif
2302-
| mov r1, aword [r1 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
23032226
| .if X64
2304-
| jmp aword [r1+r0*8]
2227+
| jmp aword [r1+r2*8+8]
23052228
| .else
2306-
| jmp aword [r1+r0*4]
2229+
| jmp aword [r1+r2*4+4]
23072230
| .endif
23082231
|1:
2309-
| .if X64
2310-
| mov word [r0+r1*2], ZEND_JIT_HOT_COUNTER_INIT
2311-
| .else
2312-
| mov word [r1*2+&zend_jit_hot_counters], ZEND_JIT_HOT_COUNTER_INIT
2313-
| .endif
23142232
| mov FCARG1a, FP
23152233
| GET_IP FCARG2a
23162234
| EXT_CALL zend_jit_hot_func, r0

0 commit comments

Comments
 (0)