/* Copyright (C) 2005-2019 Shugo Maeda and Charlie Savage Please see the LICENSE file for copyright and distribution information */ #include "rp_stack.h" #define INITIAL_STACK_SIZE 32 void prof_frame_pause(prof_frame_t *frame, double current_measurement) { if (frame && prof_frame_is_unpaused(frame)) frame->pause_time = current_measurement; } void prof_frame_unpause(prof_frame_t *frame, double current_measurement) { if (frame && prof_frame_is_paused(frame)) { frame->dead_time += (current_measurement - frame->pause_time); frame->pause_time = -1; } } /* Creates a stack of prof_frame_t to keep track of timings for active methods. */ prof_stack_t * prof_stack_create() { prof_stack_t *stack = ALLOC(prof_stack_t); stack->start = ZALLOC_N(prof_frame_t, INITIAL_STACK_SIZE); stack->ptr = stack->start; stack->end = stack->start + INITIAL_STACK_SIZE; return stack; } void prof_stack_free(prof_stack_t *stack) { xfree(stack->start); xfree(stack); } prof_frame_t * prof_stack_push(prof_stack_t *stack, prof_call_info_t *call_info, double measurement, int paused) { prof_frame_t *result; prof_frame_t* parent_frame; /* Is there space on the stack? If not, double its size. */ if (stack->ptr == stack->end - 1) { size_t len = stack->ptr - stack->start; size_t new_capacity = (stack->end - stack->start) * 2; REALLOC_N(stack->start, prof_frame_t, new_capacity); /* Memory just got moved, reset pointers */ stack->ptr = stack->start + len; stack->end = stack->start + new_capacity; } parent_frame = stack->ptr; stack->ptr++; result = stack->ptr; result->call_info = call_info; result->call_info->depth = (int)(stack->ptr - stack->start); // shortening of 64 bit into 32; result->passes = 0; result->start_time = measurement; result->pause_time = -1; // init as not paused. result->switch_time = 0; result->wait_time = 0; result->child_time = 0; result->dead_time = 0; result->source_file = Qnil; result->source_line = 0; call_info->measurement->called++; call_info->visits++; if (call_info->method->visits > 0) { call_info->method->recursive = true; } call_info->method->measurement->called++; call_info->method->visits++; // Unpause the parent frame, if it exists. // If currently paused then: // 1) The child frame will begin paused. // 2) The parent will inherit the child's dead time. prof_frame_unpause(parent_frame, measurement); if (paused) { prof_frame_pause(result, measurement); } // Return the result return result; } prof_frame_t * prof_stack_pop(prof_stack_t *stack, double measurement) { prof_frame_t *frame; prof_frame_t *parent_frame; prof_call_info_t *call_info; double total_time; double self_time; if (stack->ptr == stack->start) return NULL; frame = stack->ptr; /* Match passes until we reach the frame itself. */ if (prof_frame_is_pass(frame)) { frame->passes--; /* Additional frames can be consumed. See pop_frames(). */ return frame; } /* Consume this frame. */ stack->ptr--; parent_frame = stack->ptr; /* Calculate the total time this method took */ prof_frame_unpause(frame, measurement); total_time = measurement - frame->start_time - frame->dead_time; self_time = total_time - frame->child_time - frame->wait_time; /* Update information about the current method */ call_info = frame->call_info; // Update method measurement call_info->method->measurement->self_time += self_time; call_info->method->measurement->wait_time += frame->wait_time; if (call_info->method->visits == 1) call_info->method->measurement->total_time += total_time; call_info->method->visits--; // Update method measurement call_info->measurement->self_time += self_time; call_info->measurement->wait_time += frame->wait_time; if (call_info->visits == 1) call_info->measurement->total_time += total_time; call_info->visits--; if (parent_frame) { parent_frame->child_time += total_time; parent_frame->dead_time += frame->dead_time; } return frame; } prof_frame_t * prof_stack_pass(prof_stack_t *stack) { prof_frame_t* frame = stack->ptr; if (frame) { frame->passes++; } return frame; } prof_method_t* prof_find_method(prof_stack_t* stack, VALUE source_file, int source_line) { prof_frame_t* frame = stack->ptr; while (frame >= stack->start) { if (!frame->call_info) return NULL; if (rb_str_equal(source_file, frame->call_info->method->source_file) && source_line >= frame->call_info->method->source_line) { return frame->call_info->method; } frame--; } return NULL; }