From: Dmitry Stogov Date: Wed, 9 Dec 2015 11:52:00 +0000 (+0300) Subject: Improved optimizer dubugging facility X-Git-Tag: php-7.1.0alpha1~695 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d2597ad20bbfd94067d6798c7e396a7a063878ae;p=php Improved optimizer dubugging facility --- diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 2e797d4e7e..6aab22eff5 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -759,9 +759,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) zend_op *new_opcodes; zend_op *opline; uint32_t len = 0; -#if DEBUG_BLOCKPASS int n; -#endif for (b = blocks; b < end; b++) { if (b->flags & ZEND_BB_REACHABLE) { @@ -979,7 +977,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) *opline_num = -1; } -#if DEBUG_BLOCKPASS /* rebild map (judt for printing) */ memset(cfg->map, -1, sizeof(int) * op_array->last); for (n = 0; n < cfg->blocks_count; n++) { @@ -987,7 +984,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) cfg->map[cfg->blocks[n].start] = n; } } -#endif } static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t) @@ -1731,11 +1727,6 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_op **Tsource; zend_uchar *same_t; -#if DEBUG_BLOCKPASS - fprintf(stderr, "File %s func %s\n", op_array->filename->val, op_array->function_name ? op_array->function_name->val : "main"); - fflush(stderr); -#endif - /* Build CFG */ checkpoint = zend_arena_checkpoint(ctx->arena); if (zend_build_cfg(&ctx->arena, op_array, 0, 0, &cfg, NULL) != SUCCESS) { @@ -1743,10 +1734,9 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) return; } -#if DEBUG_BLOCKPASS - fprintf(stderr, "\nBEFORE-BLOCK-PASS: %s:\n", op_array->function_name ? op_array->function_name->val : "(null)"); - zend_dump_op_array(op_array, &cfg, 1); -#endif + if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) { + zend_dump_op_array(op_array, &cfg, ZEND_DUMP_UNREACHABLE, "before block pass"); + } if (op_array->last_var || op_array->T) { bitset_len = zend_bitset_len(op_array->last_var + op_array->T); @@ -1791,10 +1781,9 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_t_usage(&cfg, op_array, usage, ctx); assemble_code_blocks(&cfg, op_array); -#if DEBUG_BLOCKPASS - fprintf(stderr, "\nAFTER-BLOCK-PASS: %s:\n", op_array->function_name ? op_array->function_name->val : "(null)"); - zend_dump_op_array(op_array, &cfg, 0); -#endif + if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) { + zend_dump_op_array(op_array, &cfg, 0, "after block pass"); + } /* Destroy CFG */ zend_arena_release(&ctx->arena, checkpoint); diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 5966935070..e411a4bc3a 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -120,17 +120,36 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * fprintf(stderr, "\n"); } -void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, int all) +void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint32_t dump_flags, const char *msg) { int i; + if (op_array->function_name) { + if (op_array->scope && op_array->scope->name) { + fprintf(stderr, "\n%s::%s", op_array->scope->name->val, op_array->function_name->val); + } else { + fprintf(stderr, "\n%s", op_array->function_name->val); + } + } else { + fprintf(stderr, "\n%s", "$_main"); + } + fprintf(stderr, ": ; (lines=%d, args=%d, vars=%d, tmps=%d)\n", + op_array->last, + op_array->num_args, + op_array->last_var, + op_array->T); + if (msg) { + fprintf(stderr, " ; (%s)\n", msg); + } + fprintf(stderr, " ; %s:%u-%u\n", op_array->filename->val, op_array->line_start, op_array->line_end); + if (cfg) { int n; zend_basic_block *b; for (n = 0; n < cfg->blocks_count; n++) { b = cfg->blocks + n; - if (all || (b->flags & ZEND_BB_REACHABLE)) { + if ((dump_flags & ZEND_DUMP_UNREACHABLE) || (b->flags & ZEND_BB_REACHABLE)) { const zend_op *opline; const zend_op *end; int printed = 0; @@ -169,7 +188,7 @@ void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, int if (b->flags & ZEND_BB_KILL_VAR) { fprintf(stderr, " kill_var"); } - if (all & !(b->flags & ZEND_BB_REACHABLE)) { + if ((dump_flags & ZEND_DUMP_UNREACHABLE) & !(b->flags & ZEND_BB_REACHABLE)) { fprintf(stderr, " unreachable"); } diff --git a/ext/opcache/Optimizer/zend_dump.h b/ext/opcache/Optimizer/zend_dump.h index 6e2577c04f..551c834300 100644 --- a/ext/opcache/Optimizer/zend_dump.h +++ b/ext/opcache/Optimizer/zend_dump.h @@ -19,9 +19,11 @@ #ifndef ZEND_DUMP_H #define ZEND_DUMP_H +#define ZEND_DUMP_UNREACHABLE (1<<0) + BEGIN_EXTERN_C() -void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, int all); +void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint32_t dump_flags, const char *msg); END_EXTERN_C() diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 43c80e3ed2..3d238acd85 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -26,6 +26,8 @@ #include "zend_constants.h" #include "zend_execute.h" #include "zend_vm.h" +#include "zend_cfg.h" +#include "zend_dump.h" static void zend_optimizer_zval_dtor_wrapper(zval *zvalue) { @@ -529,6 +531,10 @@ static void zend_optimize(zend_op_array *op_array, return; } + if (ctx->debug_level & ZEND_DUMP_BEFORE_OPTIMIZER) { + zend_dump_op_array(op_array, NULL, 1, "before optimizer"); + } + /* pass 1 * - substitute persistent constants (true, false, null, etc) * - perform compile-time evaluation of constant binary and unary operations @@ -537,6 +543,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_1 & ctx->optimization_level) { zend_optimizer_pass1(op_array, ctx); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_1) { + zend_dump_op_array(op_array, NULL, 1, "after pass 1"); + } } /* pass 2: @@ -547,6 +556,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_2 & ctx->optimization_level) { zend_optimizer_pass2(op_array); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_2) { + zend_dump_op_array(op_array, NULL, 1, "after pass 2"); + } } /* pass 3: @@ -556,6 +568,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_3 & ctx->optimization_level) { zend_optimizer_pass3(op_array); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_3) { + zend_dump_op_array(op_array, NULL, 1, "after pass 1"); + } } /* pass 4: @@ -563,6 +578,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_4 & ctx->optimization_level) { optimize_func_calls(op_array, ctx); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_4) { + zend_dump_op_array(op_array, NULL, 1, "after pass 1"); + } } /* pass 5: @@ -570,6 +588,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_5 & ctx->optimization_level) { optimize_cfg(op_array, ctx); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_5) { + zend_dump_op_array(op_array, NULL, 1, "after pass 5"); + } } /* pass 9: @@ -577,6 +598,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_9 & ctx->optimization_level) { optimize_temporary_variables(op_array, ctx); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_9) { + zend_dump_op_array(op_array, NULL, 1, "after pass 9"); + } } /* pass 10: @@ -584,6 +608,9 @@ static void zend_optimize(zend_op_array *op_array, */ if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & ctx->optimization_level) == ZEND_OPTIMIZER_PASS_10) { zend_optimizer_nop_removal(op_array); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_10) { + zend_dump_op_array(op_array, NULL, 1, "after pass 10"); + } } /* pass 11: @@ -591,6 +618,13 @@ static void zend_optimize(zend_op_array *op_array, */ if (ZEND_OPTIMIZER_PASS_11 & ctx->optimization_level) { zend_optimizer_compact_literals(op_array, ctx); + if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_11) { + zend_dump_op_array(op_array, NULL, 1, "after pass 11"); + } + } + + if (ctx->debug_level & ZEND_DUMP_AFTER_OPTIMIZER) { + zend_dump_op_array(op_array, NULL, 1, "after optimizer"); } } @@ -650,7 +684,7 @@ static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer } } -int zend_optimize_script(zend_script *script, zend_long optimization_level) +int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level) { uint idx, j; Bucket *p, *q; @@ -662,6 +696,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level) ctx.script = script; ctx.constants = NULL; ctx.optimization_level = optimization_level; + ctx.debug_level = debug_level; zend_optimize_op_array(&script->main_op_array, &ctx); diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h index 9c2a805e76..c8e33c368e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.h +++ b/ext/opcache/Optimizer/zend_optimizer.h @@ -44,6 +44,27 @@ #define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFFFFF" + +#define ZEND_DUMP_AFTER_PASS_1 ZEND_OPTIMIZER_PASS_1 +#define ZEND_DUMP_AFTER_PASS_2 ZEND_OPTIMIZER_PASS_2 +#define ZEND_DUMP_AFTER_PASS_3 ZEND_OPTIMIZER_PASS_3 +#define ZEND_DUMP_AFTER_PASS_4 ZEND_OPTIMIZER_PASS_4 +#define ZEND_DUMP_AFTER_PASS_5 ZEND_OPTIMIZER_PASS_5 +#define ZEND_DUMP_AFTER_PASS_6 ZEND_OPTIMIZER_PASS_6 +#define ZEND_DUMP_AFTER_PASS_7 ZEND_OPTIMIZER_PASS_7 +#define ZEND_DUMP_AFTER_PASS_8 ZEND_OPTIMIZER_PASS_8 +#define ZEND_DUMP_AFTER_PASS_9 ZEND_OPTIMIZER_PASS_9 +#define ZEND_DUMP_AFTER_PASS_10 ZEND_OPTIMIZER_PASS_10 +#define ZEND_DUMP_AFTER_PASS_11 ZEND_OPTIMIZER_PASS_11 +#define ZEND_DUMP_AFTER_PASS_12 ZEND_OPTIMIZER_PASS_12 +#define ZEND_DUMP_AFTER_PASS_13 ZEND_OPTIMIZER_PASS_13 +#define ZEND_DUMP_AFTER_PASS_14 ZEND_OPTIMIZER_PASS_14 + +#define ZEND_DUMP_BEFORE_OPTIMIZER (1<<16) +#define ZEND_DUMP_AFTER_OPTIMIZER (1<<17) +#define ZEND_DUMP_BEFORE_BLOCK_PASS (1<<18) +#define ZEND_DUMP_AFTER_BLOCK_PASS (1<<19) + typedef struct _zend_script { zend_string *filename; zend_op_array main_op_array; @@ -51,6 +72,6 @@ typedef struct _zend_script { HashTable class_table; } zend_script; -int zend_optimize_script(zend_script *script, zend_long optimization_level); +int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level); #endif diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 529727d7c9..b41fe9f9e6 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -49,6 +49,7 @@ typedef struct _zend_optimizer_ctx { zend_script *script; HashTable *constants; zend_long optimization_level; + zend_long debug_level; } zend_optimizer_ctx; #define LITERAL_LONG(op, val) do { \ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 2bf05fef9f..5df11f2e24 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1157,7 +1157,7 @@ static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script return new_persistent_script; } - if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level)) { + if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) { return new_persistent_script; } @@ -1215,7 +1215,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr return new_persistent_script; } - if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level)) { + if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) { return new_persistent_script; } diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 9256212090..ae550291c5 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -191,6 +191,7 @@ typedef struct _zend_accel_directives { zend_long log_verbosity_level; zend_long optimization_level; + zend_long opt_debug_level; zend_long max_file_size; zend_long interned_strings_buffer; char *restrict_api; diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 8514e2b391..bb89020b21 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -294,6 +294,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals) STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)