| Conditions | 31 |
| Paths | 6 |
| Total Lines | 277 |
| Code Lines | 203 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php |
||
| 53 | public function execute(InputInterface $input, OutputInterface $output): int |
||
| 54 | { |
||
| 55 | $target_php_settings = $this->target_php_settings_from_console_input->createSettings($input); |
||
| 56 | $target_process_settings = $this->target_process_settings_from_console_input->createSettings($input); |
||
| 57 | |||
| 58 | $process_specifier = $this->target_process_resolver->resolve($target_process_settings); |
||
| 59 | |||
| 60 | $target_php_settings = $this->php_version_detector->decidePhpVersion( |
||
| 61 | $process_specifier, |
||
| 62 | $target_php_settings |
||
| 63 | ); |
||
| 64 | |||
| 65 | $result = $this->memory_reader->read( |
||
| 66 | $process_specifier->pid, |
||
| 67 | $main_chunk_address = $this->getChunkAddress( |
||
| 68 | $process_specifier->pid, |
||
| 69 | $target_php_settings->php_version, |
||
| 70 | $this->memory_reader |
||
| 71 | ), |
||
| 72 | 0x200000 |
||
| 73 | ); |
||
| 74 | $zend_type_reader = $this->zend_type_reader_creator->create($target_php_settings->php_version); |
||
| 75 | $zend_mm_main_chunk = $zend_type_reader->readAs('zend_mm_chunk', $result); |
||
| 76 | $size = $zend_mm_main_chunk->casted->heap_slot->size; |
||
| 77 | $real_size = $zend_mm_main_chunk->casted->heap_slot->real_size; |
||
| 78 | |||
| 79 | $eg_address = $this->php_globals_finder->findExecutorGlobals($process_specifier, $target_php_settings); |
||
| 80 | $eg_pointer = new Pointer( |
||
| 81 | ZendExecutorGlobals::class, |
||
| 82 | $eg_address, |
||
| 83 | $zend_type_reader->sizeOf('zend_executor_globals') |
||
| 84 | ); |
||
| 85 | $cg_address = $this->php_globals_finder->findCompilerGlobals($process_specifier, $target_php_settings); |
||
| 86 | $cg_pointer = new Pointer( |
||
| 87 | ZendCompilerGlobals::class, |
||
| 88 | $cg_address, |
||
| 89 | $zend_type_reader->sizeOf('zend_compiler_globals') |
||
| 90 | ); |
||
| 91 | $remote_process_dereferencer = new RemoteProcessDereferencer( |
||
| 92 | $this->memory_reader, |
||
| 93 | $process_specifier, |
||
| 94 | $casted_type_provider = new ZendCastedTypeProvider( |
||
| 95 | $zend_type_reader |
||
| 96 | ), |
||
| 97 | ); |
||
| 98 | /** @var ZendExecutorGlobals $eg */ |
||
| 99 | $eg = $remote_process_dereferencer->deref($eg_pointer); |
||
| 100 | $function_table = $remote_process_dereferencer->deref($eg->function_table); |
||
| 101 | $class_table = $remote_process_dereferencer->deref($eg->class_table); |
||
| 102 | $zend_constants = $remote_process_dereferencer->deref($eg->zend_constants); |
||
| 103 | |||
| 104 | $vm_stack_curent = $remote_process_dereferencer->deref($eg->vm_stack); |
||
| 105 | $vm_stack_size = 0; |
||
| 106 | foreach ($vm_stack_curent->iterateStackChain($remote_process_dereferencer) as $vm_stack) { |
||
| 107 | $vm_stack_size += $vm_stack->getSize(); |
||
| 108 | } |
||
| 109 | /** @var ZendCompilerGlobals $cg */ |
||
| 110 | $cg = $remote_process_dereferencer->deref($cg_pointer); |
||
| 111 | |||
| 112 | $dump_symbol_table = function (ZendArray $array) use (&$dump_symbol_table, $remote_process_dereferencer, &$dump_zval) { |
||
| 113 | $result = []; |
||
| 114 | $pos = 0; |
||
| 115 | foreach ($array->getItemIterator($remote_process_dereferencer) as $key => $zval) { |
||
| 116 | $key_name = $key ?? $pos++; |
||
| 117 | $result[$key_name] = $dump_zval($zval); |
||
| 118 | } |
||
| 119 | return $result; |
||
| 120 | }; |
||
| 121 | $dump_function_table = function (ZendArray $array) use ($dump_symbol_table, $remote_process_dereferencer) { |
||
| 122 | $result = []; |
||
| 123 | $pos = 0; |
||
| 124 | foreach ($array->getItemIterator($remote_process_dereferencer) as $key => $zval) { |
||
| 125 | $function_name = $key ?? $pos++; |
||
| 126 | $func = $remote_process_dereferencer->deref($zval->value->func); |
||
| 127 | if ($func->type === 2) { |
||
| 128 | $static_variables = []; |
||
| 129 | if (!is_null($func->op_array->static_variables)) { |
||
| 130 | $static_variables = $dump_symbol_table( |
||
| 131 | $remote_process_dereferencer->deref($func->op_array->static_variables) |
||
| 132 | ); |
||
| 133 | } |
||
| 134 | $result[$function_name] = [ |
||
| 135 | 'op_array_size' => $func->op_array->last * 48, |
||
| 136 | 'static_variables' => $static_variables, |
||
| 137 | 'overhead' => 128, |
||
| 138 | ]; |
||
| 139 | } |
||
| 140 | } |
||
| 141 | return $result; |
||
| 142 | }; |
||
| 143 | $dump_class_constants_table = function (ZendClassEntry $ce) use ($remote_process_dereferencer, $dump_symbol_table, $zend_type_reader, &$dump_zval) { |
||
| 144 | $result = []; |
||
| 145 | $pos = 0; |
||
| 146 | foreach ($ce->constants_table->getItemIterator($remote_process_dereferencer) as $key => $zval_ptr) { |
||
| 147 | $constant_name = $key ?? $pos++; |
||
| 148 | $class_constant_ptr = $zval_ptr->value->getAsPointer( |
||
| 149 | ZendClassConstant::class, |
||
| 150 | $zend_type_reader->sizeOf(ZendClassConstant::getCTypeName()), |
||
| 151 | ); |
||
| 152 | $class_constant = $remote_process_dereferencer->deref( |
||
| 153 | $class_constant_ptr |
||
| 154 | ); |
||
| 155 | |||
| 156 | $zval = $class_constant->value; |
||
| 157 | $result[$constant_name] = $dump_zval($zval); |
||
| 158 | } |
||
| 159 | return $result; |
||
| 160 | }; |
||
| 161 | $dump_class_table = function (ZendArray $array) use ($dump_symbol_table, $dump_function_table, $dump_class_constants_table, $remote_process_dereferencer, $zend_type_reader, &$dump_zval) { |
||
| 162 | $result = []; |
||
| 163 | $pos = 0; |
||
| 164 | foreach ($array->getItemIterator($remote_process_dereferencer) as $key => $zval) { |
||
| 165 | $class_name = $key ?? $pos++; |
||
| 166 | /** @var ZendClassEntry $class_entry */ |
||
| 167 | $class_entry = $remote_process_dereferencer->deref($zval->value->ce); |
||
| 168 | if ($class_entry->isInternal()) { |
||
| 169 | continue; |
||
| 170 | } |
||
| 171 | $analyzed_static_member_table = []; |
||
| 172 | $static_property_iterator = $class_entry->getStaticPropertyIterator( |
||
| 173 | $remote_process_dereferencer, |
||
| 174 | $zend_type_reader |
||
| 175 | ); |
||
| 176 | foreach ($static_property_iterator as $name => $value) { |
||
| 177 | if (!is_null($value)) { |
||
| 178 | $analyzed_static_member_table[$name] = $dump_zval($value); |
||
| 179 | } else { |
||
| 180 | $analyzed_static_member_table[$name] = 16; |
||
| 181 | } |
||
| 182 | } |
||
| 183 | $result[$class_name] = [ |
||
| 184 | 'static_variables' => $analyzed_static_member_table, |
||
| 185 | 'methods' => $dump_function_table($class_entry->function_table), |
||
| 186 | 'constants' => $dump_class_constants_table($class_entry), |
||
| 187 | 'overhead' => 128, |
||
| 188 | ]; |
||
| 189 | } |
||
| 190 | return $result; |
||
| 191 | }; |
||
| 192 | $recursion_memo = []; |
||
| 193 | $dump_zval = function (Zval $zval) use (&$dump_zval, &$recursion_memo, $remote_process_dereferencer, &$dump_symbol_table, $zend_type_reader): int|array { |
||
| 194 | if ($zval->isArray()) { |
||
| 195 | $pos = 0; |
||
| 196 | $result = []; |
||
| 197 | if (isset($recursion_memo[$zval->value->arr->address])) { |
||
| 198 | return [$zval->value->arr->address => 16]; |
||
| 199 | } |
||
| 200 | $recursion_memo[$zval->value->arr->address] = true; |
||
| 201 | $array = $remote_process_dereferencer->deref($zval->value->arr); |
||
| 202 | foreach ($array->getItemIterator($remote_process_dereferencer) as $key => $zval) { |
||
| 203 | $key_name = $key ?? $pos++; |
||
| 204 | $result[$key_name] = $dump_zval($zval); |
||
| 205 | } |
||
| 206 | |||
| 207 | return [ |
||
| 208 | 'address' => $zval->value->arr->address, |
||
| 209 | 'overhead' => 64, |
||
| 210 | 'items' => $result, |
||
| 211 | ]; |
||
| 212 | } elseif ($zval->isObject()) { |
||
| 213 | if (isset($recursion_memo[$zval->value->obj->address])) { |
||
| 214 | return [$zval->value->obj->address => 16]; |
||
| 215 | } |
||
| 216 | $recursion_memo[$zval->value->obj->address] = true; |
||
| 217 | $obj = $remote_process_dereferencer->deref($zval->value->obj); |
||
| 218 | $dynamic_properties = []; |
||
| 219 | if (!is_null($obj->properties) and !is_null($obj->ce) and !$obj->isEnum($remote_process_dereferencer)) { |
||
| 220 | $dynamic_properties = $dump_symbol_table( |
||
| 221 | $remote_process_dereferencer->deref($obj->properties), |
||
| 222 | ); |
||
| 223 | } |
||
| 224 | $properties = []; |
||
| 225 | $properties_iterator = $obj->getPropertiesIterator( |
||
| 226 | $remote_process_dereferencer, |
||
| 227 | $zend_type_reader, |
||
| 228 | $zval->value->obj, |
||
| 229 | ); |
||
| 230 | foreach ($properties_iterator as $name => $property) { |
||
| 231 | $properties[$name] = $dump_zval($property); |
||
| 232 | } |
||
| 233 | |||
| 234 | return [ |
||
| 235 | 'address' => $zval->value->obj->address, |
||
| 236 | 'overhead' => 128, |
||
| 237 | 'dynamic_properties' => $dynamic_properties, |
||
| 238 | 'properties' => $properties, |
||
| 239 | ]; |
||
| 240 | } elseif ($zval->isString()) { |
||
| 241 | $str = $remote_process_dereferencer->deref($zval->value->str); |
||
| 242 | return [ |
||
| 243 | 'address' => $zval->value->str->address, |
||
| 244 | 'overhead' => 128, |
||
| 245 | 'len' => $str->len, |
||
| 246 | ]; |
||
| 247 | } else { |
||
| 248 | return 16; |
||
| 249 | } |
||
| 250 | }; |
||
| 251 | |||
| 252 | $call_frames = []; |
||
| 253 | $execute_data = $remote_process_dereferencer->deref($eg->current_execute_data); |
||
| 254 | foreach ($execute_data->iterateStackChain($remote_process_dereferencer) as $execute_data) { |
||
| 255 | $current_function_name = $execute_data->getFunctionName($remote_process_dereferencer); |
||
| 256 | $current_call_frame = []; |
||
| 257 | $local_variables_iterator = $execute_data->getVariables($remote_process_dereferencer, $zend_type_reader); |
||
| 258 | foreach ($local_variables_iterator as $name => $value) { |
||
| 259 | $current_call_frame[$name] = $dump_zval($value); |
||
| 260 | } |
||
| 261 | $call_frames[] = [ |
||
| 262 | 'function_name' => $current_function_name, |
||
| 263 | 'local_variables' => $current_call_frame, |
||
| 264 | ]; |
||
| 265 | } |
||
| 266 | $pick_heap_allocated = function (array $call_frames) { |
||
| 267 | $result = []; |
||
| 268 | foreach ($call_frames as $key => $frame) { |
||
| 269 | $local_variables = []; |
||
| 270 | foreach ($frame['local_variables'] as $name => $variable) { |
||
| 271 | if (isset($variable['address'])) { |
||
| 272 | $local_variables[$name] = $variable; |
||
| 273 | } |
||
| 274 | if (is_int($variable)) { |
||
| 275 | $local_variables[$name] = 'stack allocated'; |
||
| 276 | } |
||
| 277 | } |
||
| 278 | $result[$key] = [ |
||
| 279 | 'function_name' => $frame['function_name'], |
||
| 280 | 'local_variables' => $local_variables, |
||
| 281 | ]; |
||
| 282 | } |
||
| 283 | return $result; |
||
| 284 | }; |
||
| 285 | |||
| 286 | $sum = function (array $result) use (&$sum) { |
||
| 287 | $total = 0; |
||
| 288 | foreach ($result as $key => $item) { |
||
| 289 | if (is_array($item)) { |
||
| 290 | $total += $sum($item); |
||
| 291 | } elseif ($key !== 'address' and is_int($item)) { |
||
| 292 | $total += $item; |
||
| 293 | } |
||
| 294 | } |
||
| 295 | return $total; |
||
| 296 | }; |
||
| 297 | $symbol_table_result = $dump_symbol_table($eg->symbol_table); |
||
| 298 | $function_table_result = $dump_function_table($function_table); |
||
| 299 | $class_table_result = $dump_class_table($class_table); |
||
| 300 | $compiler_arena = $cg->getSizeOfArena($remote_process_dereferencer); |
||
| 301 | $compiler_ast_arena = $cg->getSizeOfAstArena($remote_process_dereferencer); |
||
| 302 | $data_traced = [ |
||
| 303 | 'call_frames' => $call_frames, |
||
| 304 | 'global_variables' => $symbol_table_result, |
||
| 305 | 'functions' => $function_table_result, |
||
| 306 | 'classes' => $class_table_result, |
||
| 307 | ]; |
||
| 308 | // var_dump($data_traced); |
||
| 309 | // var_dump($call_frames); |
||
| 310 | // die; |
||
| 311 | $analyzed_result = [ |
||
| 312 | 'call_frames' => $sum($pick_heap_allocated($call_frames)), |
||
| 313 | 'global_variables' => $sum($symbol_table_result), |
||
| 314 | 'functions' => $sum($function_table_result), |
||
| 315 | 'classes' => $sum($class_table_result), |
||
| 316 | 'vm_stack' => $vm_stack_size, |
||
| 317 | 'compiler_arena' => $compiler_arena, |
||
| 318 | 'compiler_ast_arena' => $compiler_ast_arena, |
||
| 319 | ]; |
||
| 320 | file_put_contents('traced_data.json', json_encode($data_traced, JSON_PRETTY_PRINT)); |
||
| 321 | var_dump($analyzed_result); |
||
|
|
|||
| 322 | |||
| 323 | var_dump([ |
||
| 324 | 'heap_size' => $size, |
||
| 325 | 'heap_real_size' => $real_size, |
||
| 326 | 'analyzed_sum' => $sum($analyzed_result), |
||
| 327 | 'analyzed_percentage' => $sum($analyzed_result) / $size * 100, |
||
| 328 | ]); |
||
| 329 | return 0; |
||
| 330 | } |
||
| 345 |