ruby-prof 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +13 -0
- data/ext/ruby_prof/rp_allocation.c +136 -81
- data/ext/ruby_prof/rp_allocation.h +8 -6
- data/ext/ruby_prof/rp_call_tree.c +8 -1
- data/ext/ruby_prof/rp_measurement.c +10 -3
- data/ext/ruby_prof/rp_method.c +51 -76
- data/ext/ruby_prof/rp_profile.c +62 -77
- data/ext/ruby_prof/rp_profile.h +1 -0
- data/ext/ruby_prof/rp_thread.c +14 -4
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +1 -1
- data/lib/ruby-prof/compatibility.rb +14 -0
- data/lib/ruby-prof/printers/abstract_printer.rb +1 -1
- data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
- data/lib/ruby-prof/printers/multi_printer.rb +17 -17
- data/lib/ruby-prof/profile.rb +5 -5
- data/lib/ruby-prof/rack.rb +31 -21
- data/lib/ruby-prof/version.rb +1 -1
- data/test/abstract_printer_test.rb +1 -0
- data/test/alias_test.rb +6 -11
- data/test/call_tree_visitor_test.rb +1 -6
- data/test/call_trees_test.rb +2 -2
- data/test/{basic_test.rb → compatibility_test.rb} +8 -2
- data/test/duplicate_names_test.rb +1 -1
- data/test/dynamic_method_test.rb +1 -6
- data/test/enumerable_test.rb +1 -1
- data/test/exceptions_test.rb +2 -2
- data/test/exclude_methods_test.rb +3 -8
- data/test/exclude_threads_test.rb +4 -9
- data/test/fiber_test.rb +4 -9
- data/test/gc_test.rb +2 -1
- data/test/inverse_call_tree_test.rb +33 -34
- data/test/line_number_test.rb +1 -1
- data/test/marshal_test.rb +3 -3
- data/test/measure_allocations_test.rb +8 -17
- data/test/measure_memory_test.rb +3 -12
- data/test/measure_process_time_test.rb +29 -34
- data/test/measure_wall_time_test.rb +176 -181
- data/test/multi_printer_test.rb +0 -5
- data/test/no_method_class_test.rb +1 -1
- data/test/pause_resume_test.rb +12 -16
- data/test/printer_call_stack_test.rb +2 -2
- data/test/printer_call_tree_test.rb +2 -2
- data/test/printer_flat_test.rb +1 -1
- data/test/printer_graph_html_test.rb +2 -2
- data/test/printer_graph_test.rb +2 -2
- data/test/printers_test.rb +14 -20
- data/test/printing_recursive_graph_test.rb +2 -2
- data/test/recursive_test.rb +2 -7
- data/test/singleton_test.rb +1 -1
- data/test/stack_printer_test.rb +5 -8
- data/test/start_stop_test.rb +11 -14
- data/test/thread_test.rb +13 -15
- data/test/unique_call_path_test.rb +4 -4
- data/test/yarv_test.rb +3 -3
- metadata +4 -4
    
        data/ext/ruby_prof/rp_profile.c
    CHANGED
    
    | @@ -103,17 +103,15 @@ static int excludes_method(st_data_t key, prof_profile_t* profile) | |
| 103 103 | 
             
                        method_table_lookup(profile->exclude_methods_tbl, key) != NULL);
         | 
| 104 104 | 
             
            }
         | 
| 105 105 |  | 
| 106 | 
            -
            static prof_method_t* create_method( | 
| 106 | 
            +
            static prof_method_t* create_method(prof_profile_t* profile, st_data_t key, VALUE klass, VALUE msym, VALUE source_file, int source_line)
         | 
| 107 107 | 
             
            {
         | 
| 108 | 
            -
                prof_method_t* result = prof_method_create(profile, klass, msym, source_file, source_line);
         | 
| 109 | 
            -
             | 
| 110 | 
            -
                prof_profile_t* profile_t = prof_get_profile(profile);
         | 
| 111 | 
            -
                method_table_insert(profile_t->last_thread_data->method_table, result->key, result);
         | 
| 108 | 
            +
                prof_method_t* result = prof_method_create(profile->object, klass, msym, source_file, source_line);
         | 
| 109 | 
            +
                method_table_insert(profile->last_thread_data->method_table, result->key, result);
         | 
| 112 110 |  | 
| 113 111 | 
             
                return result;
         | 
| 114 112 | 
             
            }
         | 
| 115 113 |  | 
| 116 | 
            -
            static prof_method_t* check_parent_method( | 
| 114 | 
            +
            static prof_method_t* check_parent_method(prof_profile_t* profile, thread_data_t* thread_data)
         | 
| 117 115 | 
             
            {
         | 
| 118 116 | 
             
                VALUE msym = ID2SYM(rb_intern("_inserted_parent_"));
         | 
| 119 117 | 
             
                st_data_t key = method_key(cProfile, msym);
         | 
| @@ -128,7 +126,7 @@ static prof_method_t* check_parent_method(VALUE profile, thread_data_t* thread_d | |
| 128 126 | 
             
                return result;
         | 
| 129 127 | 
             
            }
         | 
| 130 128 |  | 
| 131 | 
            -
            prof_method_t* check_method( | 
| 129 | 
            +
            prof_method_t* check_method(prof_profile_t* profile, rb_trace_arg_t* trace_arg, rb_event_flag_t event, thread_data_t* thread_data)
         | 
| 132 130 | 
             
            {
         | 
| 133 131 | 
             
                VALUE klass = rb_tracearg_defined_class(trace_arg);
         | 
| 134 132 |  | 
| @@ -142,8 +140,7 @@ prof_method_t* check_method(VALUE profile, rb_trace_arg_t* trace_arg, rb_event_f | |
| 142 140 |  | 
| 143 141 | 
             
                st_data_t key = method_key(klass, msym);
         | 
| 144 142 |  | 
| 145 | 
            -
                 | 
| 146 | 
            -
                if (excludes_method(key, profile_t))
         | 
| 143 | 
            +
                if (excludes_method(key, profile))
         | 
| 147 144 | 
             
                    return NULL;
         | 
| 148 145 |  | 
| 149 146 | 
             
                prof_method_t* result = method_table_lookup(thread_data->method_table, key);
         | 
| @@ -197,17 +194,16 @@ static void prof_trace(prof_profile_t* profile, rb_trace_arg_t* trace_arg, doubl | |
| 197 194 |  | 
| 198 195 | 
             
            static void prof_event_hook(VALUE trace_point, void* data)
         | 
| 199 196 | 
             
            {
         | 
| 200 | 
            -
                 | 
| 201 | 
            -
                prof_profile_t* profile_t = prof_get_profile(profile);
         | 
| 197 | 
            +
                prof_profile_t* profile = (prof_profile_t*)(data);
         | 
| 202 198 |  | 
| 203 199 | 
             
                rb_trace_arg_t* trace_arg = rb_tracearg_from_tracepoint(trace_point);
         | 
| 204 | 
            -
                double measurement = prof_measure( | 
| 200 | 
            +
                double measurement = prof_measure(profile->measurer, trace_arg);
         | 
| 205 201 | 
             
                rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
         | 
| 206 202 | 
             
                VALUE self = rb_tracearg_self(trace_arg);
         | 
| 207 203 |  | 
| 208 204 | 
             
                if (trace_file != NULL)
         | 
| 209 205 | 
             
                {
         | 
| 210 | 
            -
                    prof_trace( | 
| 206 | 
            +
                    prof_trace(profile, trace_arg, measurement);
         | 
| 211 207 | 
             
                }
         | 
| 212 208 |  | 
| 213 209 | 
             
                /* Special case - skip any methods from the mProf
         | 
| @@ -215,7 +211,7 @@ static void prof_event_hook(VALUE trace_point, void* data) | |
| 215 211 | 
             
                if (self == mProf)
         | 
| 216 212 | 
             
                    return;
         | 
| 217 213 |  | 
| 218 | 
            -
                thread_data_t* thread_data = check_fiber( | 
| 214 | 
            +
                thread_data_t* thread_data = check_fiber(profile, measurement);
         | 
| 219 215 |  | 
| 220 216 | 
             
                if (!thread_data->trace)
         | 
| 221 217 | 
             
                    return;
         | 
| @@ -247,7 +243,7 @@ static void prof_event_hook(VALUE trace_point, void* data) | |
| 247 243 | 
             
                            // This is the first method to be profiled
         | 
| 248 244 | 
             
                            else
         | 
| 249 245 | 
             
                            {
         | 
| 250 | 
            -
                                frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST( | 
| 246 | 
            +
                                frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile->paused));
         | 
| 251 247 | 
             
                            }
         | 
| 252 248 |  | 
| 253 249 | 
             
                            thread_data->call_tree = call_tree;
         | 
| @@ -301,7 +297,7 @@ static void prof_event_hook(VALUE trace_point, void* data) | |
| 301 297 | 
             
                            thread_data->call_tree = call_tree;
         | 
| 302 298 |  | 
| 303 299 | 
             
                        // Push a new frame onto the stack for a new c-call or ruby call (into a method)
         | 
| 304 | 
            -
                        prof_frame_t* next_frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST( | 
| 300 | 
            +
                        prof_frame_t* next_frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile->paused));
         | 
| 305 301 | 
             
                        next_frame->source_file = method->source_file;
         | 
| 306 302 | 
             
                        next_frame->source_line = method->source_line;
         | 
| 307 303 | 
             
                        break;
         | 
| @@ -327,7 +323,7 @@ static void prof_event_hook(VALUE trace_point, void* data) | |
| 327 323 |  | 
| 328 324 | 
             
                        prof_method_t* method = prof_find_method(thread_data->stack, source_file, source_line);
         | 
| 329 325 | 
             
                        if (method)
         | 
| 330 | 
            -
                            prof_allocate_increment(method, trace_arg);
         | 
| 326 | 
            +
                            prof_allocate_increment(method->allocations_table, trace_arg);
         | 
| 331 327 |  | 
| 332 328 | 
             
                        break;
         | 
| 333 329 | 
             
                    }
         | 
| @@ -342,12 +338,12 @@ void prof_install_hook(VALUE self) | |
| 342 338 | 
             
                                                           RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
         | 
| 343 339 | 
             
                                                           RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
         | 
| 344 340 | 
             
                                                           RUBY_EVENT_LINE,
         | 
| 345 | 
            -
                                                           prof_event_hook,  | 
| 341 | 
            +
                                                           prof_event_hook, profile);
         | 
| 346 342 | 
             
                rb_ary_push(profile->tracepoints, event_tracepoint);
         | 
| 347 343 |  | 
| 348 344 | 
             
                if (profile->measurer->track_allocations)
         | 
| 349 345 | 
             
                {
         | 
| 350 | 
            -
                    VALUE allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, prof_event_hook,  | 
| 346 | 
            +
                    VALUE allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, prof_event_hook, profile);
         | 
| 351 347 | 
             
                    rb_ary_push(profile->tracepoints, allocation_tracepoint);
         | 
| 352 348 | 
             
                }
         | 
| 353 349 |  | 
| @@ -404,9 +400,10 @@ static int prof_profile_mark_methods(st_data_t key, st_data_t value, st_data_t r | |
| 404 400 | 
             
            static void prof_profile_mark(void* data)
         | 
| 405 401 | 
             
            {
         | 
| 406 402 | 
             
                prof_profile_t* profile = (prof_profile_t*)data;
         | 
| 407 | 
            -
                 | 
| 408 | 
            -
                 | 
| 409 | 
            -
                 | 
| 403 | 
            +
                rb_gc_mark_movable(profile->object);
         | 
| 404 | 
            +
                rb_gc_mark_movable(profile->tracepoints);
         | 
| 405 | 
            +
                rb_gc_mark_movable(profile->running);
         | 
| 406 | 
            +
                rb_gc_mark_movable(profile->paused);
         | 
| 410 407 |  | 
| 411 408 | 
             
                // If GC stress is true (useful for debugging), when threads_table_create is called in the
         | 
| 412 409 | 
             
                // allocate method Ruby will immediately call this mark method. Thus the threads_tbl will be NULL.
         | 
| @@ -417,6 +414,15 @@ static void prof_profile_mark(void* data) | |
| 417 414 | 
             
                    rb_st_foreach(profile->exclude_methods_tbl, prof_profile_mark_methods, 0);
         | 
| 418 415 | 
             
            }
         | 
| 419 416 |  | 
| 417 | 
            +
            void prof_profile_compact(void* data)
         | 
| 418 | 
            +
            {
         | 
| 419 | 
            +
                prof_profile_t* profile = (prof_profile_t*)data;
         | 
| 420 | 
            +
                profile->object = rb_gc_location(profile->object);
         | 
| 421 | 
            +
                profile->tracepoints = rb_gc_location(profile->tracepoints);
         | 
| 422 | 
            +
                profile->running = rb_gc_location(profile->running);
         | 
| 423 | 
            +
                profile->paused = rb_gc_location(profile->paused);
         | 
| 424 | 
            +
            }
         | 
| 425 | 
            +
             | 
| 420 426 | 
             
            /* Freeing the profile creates a cascade of freeing. It frees its threads table, which frees
         | 
| 421 427 | 
             
               each thread and its associated call treee and methods. */
         | 
| 422 428 | 
             
            static void prof_profile_ruby_gc_free(void* data)
         | 
| @@ -462,6 +468,7 @@ static const rb_data_type_t profile_type = | |
| 462 468 | 
             
                    .dmark = prof_profile_mark,
         | 
| 463 469 | 
             
                    .dfree = prof_profile_ruby_gc_free,
         | 
| 464 470 | 
             
                    .dsize = prof_profile_size,
         | 
| 471 | 
            +
                    .dcompact = prof_profile_compact
         | 
| 465 472 | 
             
                },
         | 
| 466 473 | 
             
                .data = NULL,
         | 
| 467 474 | 
             
                .flags = RUBY_TYPED_FREE_IMMEDIATELY
         | 
| @@ -472,6 +479,7 @@ static VALUE prof_allocate(VALUE klass) | |
| 472 479 | 
             
                VALUE result;
         | 
| 473 480 | 
             
                prof_profile_t* profile;
         | 
| 474 481 | 
             
                result = TypedData_Make_Struct(klass, prof_profile_t, &profile_type, profile);
         | 
| 482 | 
            +
                profile->object = result;
         | 
| 475 483 | 
             
                profile->threads_tbl = threads_table_create();
         | 
| 476 484 | 
             
                profile->exclude_threads_tbl = NULL;
         | 
| 477 485 | 
             
                profile->include_threads_tbl = NULL;
         | 
| @@ -510,9 +518,9 @@ prof_stop_threads(prof_profile_t* profile) | |
| 510 518 |  | 
| 511 519 | 
             
            /* call-seq:
         | 
| 512 520 | 
             
               new()
         | 
| 513 | 
            -
               new( | 
| 521 | 
            +
               new(keyword_args)
         | 
| 514 522 |  | 
| 515 | 
            -
               Returns a new profiler. Possible  | 
| 523 | 
            +
               Returns a new profiler. Possible keyword arguments include:
         | 
| 516 524 |  | 
| 517 525 | 
             
               measure_mode:      Measure mode. Specifies the profile measure mode.
         | 
| 518 526 | 
             
                                  If not specified, defaults to RubyProf::WALL_TIME.
         | 
| @@ -525,78 +533,55 @@ prof_stop_threads(prof_profile_t* profile) | |
| 525 533 | 
             
                                  all other threads. */
         | 
| 526 534 | 
             
            static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
         | 
| 527 535 | 
             
            {
         | 
| 536 | 
            +
                VALUE keywords;
         | 
| 537 | 
            +
                rb_scan_args_kw(RB_SCAN_ARGS_KEYWORDS, argc, argv, ":", &keywords);
         | 
| 538 | 
            +
             | 
| 539 | 
            +
                ID table[] = {rb_intern("measure_mode"),
         | 
| 540 | 
            +
                              rb_intern("track_allocations"),
         | 
| 541 | 
            +
                              rb_intern("allow_exceptions"),
         | 
| 542 | 
            +
                              rb_intern("exclude_common"),
         | 
| 543 | 
            +
                              rb_intern("exclude_threads"),
         | 
| 544 | 
            +
                              rb_intern("include_threads") };
         | 
| 545 | 
            +
                VALUE values[6];
         | 
| 546 | 
            +
                rb_get_kwargs(keywords, table, 0, 6, values);
         | 
| 547 | 
            +
             | 
| 548 | 
            +
                VALUE mode = values[0] == Qundef ? INT2NUM(MEASURE_WALL_TIME) : values[0];
         | 
| 549 | 
            +
                VALUE track_allocations = values[1] == Qtrue ? Qtrue : Qfalse;
         | 
| 550 | 
            +
                VALUE allow_exceptions = values[2] == Qtrue ? Qtrue : Qfalse;
         | 
| 551 | 
            +
                VALUE exclude_common = values[3] == Qtrue ? Qtrue : Qfalse;
         | 
| 552 | 
            +
                VALUE exclude_threads = values[4];
         | 
| 553 | 
            +
                VALUE include_threads = values[5];
         | 
| 554 | 
            +
             | 
| 555 | 
            +
                Check_Type(mode, T_FIXNUM);
         | 
| 528 556 | 
             
                prof_profile_t* profile = prof_get_profile(self);
         | 
| 529 | 
            -
                 | 
| 530 | 
            -
                 | 
| 531 | 
            -
                VALUE exclude_threads = Qnil;
         | 
| 532 | 
            -
                VALUE include_threads = Qnil;
         | 
| 533 | 
            -
                VALUE exclude_common = Qnil;
         | 
| 534 | 
            -
                VALUE allow_exceptions = Qfalse;
         | 
| 535 | 
            -
                VALUE track_allocations = Qfalse;
         | 
| 536 | 
            -
             | 
| 537 | 
            -
                int i;
         | 
| 538 | 
            -
             | 
| 539 | 
            -
                switch (rb_scan_args(argc, argv, "02", &mode_or_options, &exclude_threads))
         | 
| 540 | 
            -
                {
         | 
| 541 | 
            -
                case 0:
         | 
| 542 | 
            -
                    break;
         | 
| 543 | 
            -
                case 1:
         | 
| 544 | 
            -
                    if (FIXNUM_P(mode_or_options))
         | 
| 545 | 
            -
                    {
         | 
| 546 | 
            -
                        mode = mode_or_options;
         | 
| 547 | 
            -
                    }
         | 
| 548 | 
            -
                    else
         | 
| 549 | 
            -
                    {
         | 
| 550 | 
            -
                        Check_Type(mode_or_options, T_HASH);
         | 
| 551 | 
            -
                        mode = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("measure_mode")));
         | 
| 552 | 
            -
                        track_allocations = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("track_allocations")));
         | 
| 553 | 
            -
                        allow_exceptions = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("allow_exceptions")));
         | 
| 554 | 
            -
                        exclude_common = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("exclude_common")));
         | 
| 555 | 
            -
                        exclude_threads = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("exclude_threads")));
         | 
| 556 | 
            -
                        include_threads = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("include_threads")));
         | 
| 557 | 
            -
                    }
         | 
| 558 | 
            -
                    break;
         | 
| 559 | 
            -
                case 2:
         | 
| 560 | 
            -
                    Check_Type(exclude_threads, T_ARRAY);
         | 
| 561 | 
            -
                    break;
         | 
| 562 | 
            -
                }
         | 
| 563 | 
            -
             | 
| 564 | 
            -
                if (mode == Qnil)
         | 
| 565 | 
            -
                {
         | 
| 566 | 
            -
                    mode = INT2NUM(MEASURE_WALL_TIME);
         | 
| 567 | 
            -
                }
         | 
| 568 | 
            -
                else
         | 
| 569 | 
            -
                {
         | 
| 570 | 
            -
                    Check_Type(mode, T_FIXNUM);
         | 
| 571 | 
            -
                }
         | 
| 572 | 
            -
                profile->measurer = prof_measurer_create(NUM2INT(mode), track_allocations == Qtrue);
         | 
| 573 | 
            -
                profile->allow_exceptions = (allow_exceptions == Qtrue);
         | 
| 557 | 
            +
                profile->measurer = prof_measurer_create(NUM2INT(mode), RB_TEST(track_allocations));
         | 
| 558 | 
            +
                profile->allow_exceptions = RB_TEST(allow_exceptions);
         | 
| 574 559 |  | 
| 575 | 
            -
                if (exclude_threads !=  | 
| 560 | 
            +
                if (exclude_threads != Qundef)
         | 
| 576 561 | 
             
                {
         | 
| 577 562 | 
             
                    Check_Type(exclude_threads, T_ARRAY);
         | 
| 578 563 | 
             
                    assert(profile->exclude_threads_tbl == NULL);
         | 
| 579 564 | 
             
                    profile->exclude_threads_tbl = threads_table_create();
         | 
| 580 | 
            -
                    for (i = 0; i < RARRAY_LEN(exclude_threads); i++)
         | 
| 565 | 
            +
                    for (int i = 0; i < RARRAY_LEN(exclude_threads); i++)
         | 
| 581 566 | 
             
                    {
         | 
| 582 567 | 
             
                        VALUE thread = rb_ary_entry(exclude_threads, i);
         | 
| 583 568 | 
             
                        rb_st_insert(profile->exclude_threads_tbl, thread, Qtrue);
         | 
| 584 569 | 
             
                    }
         | 
| 585 570 | 
             
                }
         | 
| 586 571 |  | 
| 587 | 
            -
                if (include_threads !=  | 
| 572 | 
            +
                if (include_threads != Qundef)
         | 
| 588 573 | 
             
                {
         | 
| 589 574 | 
             
                    Check_Type(include_threads, T_ARRAY);
         | 
| 590 575 | 
             
                    assert(profile->include_threads_tbl == NULL);
         | 
| 591 576 | 
             
                    profile->include_threads_tbl = threads_table_create();
         | 
| 592 | 
            -
                    for (i = 0; i < RARRAY_LEN(include_threads); i++)
         | 
| 577 | 
            +
                    for (int i = 0; i < RARRAY_LEN(include_threads); i++)
         | 
| 593 578 | 
             
                    {
         | 
| 594 579 | 
             
                        VALUE thread = rb_ary_entry(include_threads, i);
         | 
| 595 580 | 
             
                        rb_st_insert(profile->include_threads_tbl, thread, Qtrue);
         | 
| 596 581 | 
             
                    }
         | 
| 597 582 | 
             
                }
         | 
| 598 583 |  | 
| 599 | 
            -
                if ( | 
| 584 | 
            +
                if (RB_TEST(exclude_common))
         | 
| 600 585 | 
             
                {
         | 
| 601 586 | 
             
                    prof_exclude_common_methods(self);
         | 
| 602 587 | 
             
                }
         | 
| @@ -820,7 +805,7 @@ static VALUE prof_remove_thread(VALUE self, VALUE thread) | |
| 820 805 | 
             
                   ..
         | 
| 821 806 | 
             
                 end
         | 
| 822 807 | 
             
            */
         | 
| 823 | 
            -
            static VALUE  | 
| 808 | 
            +
            static VALUE prof_profile_instance(VALUE self)
         | 
| 824 809 | 
             
            {
         | 
| 825 810 | 
             
                int result;
         | 
| 826 811 | 
             
                prof_profile_t* profile = prof_get_profile(self);
         | 
| @@ -856,7 +841,7 @@ static VALUE prof_profile_object(VALUE self) | |
| 856 841 | 
             
            */
         | 
| 857 842 | 
             
            static VALUE prof_profile_class(int argc, VALUE* argv, VALUE klass)
         | 
| 858 843 | 
             
            {
         | 
| 859 | 
            -
                return  | 
| 844 | 
            +
                return prof_profile_instance(rb_class_new_instance(argc, argv, cProfile));
         | 
| 860 845 | 
             
            }
         | 
| 861 846 |  | 
| 862 847 | 
             
            /* call-seq:
         | 
| @@ -927,7 +912,7 @@ void rp_init_profile(void) | |
| 927 912 |  | 
| 928 913 | 
             
                rb_define_singleton_method(cProfile, "profile", prof_profile_class, -1);
         | 
| 929 914 | 
             
                rb_define_method(cProfile, "initialize", prof_initialize, -1);
         | 
| 930 | 
            -
                rb_define_method(cProfile, "profile",  | 
| 915 | 
            +
                rb_define_method(cProfile, "profile", prof_profile_instance, 0);
         | 
| 931 916 | 
             
                rb_define_method(cProfile, "start", prof_start, 0);
         | 
| 932 917 | 
             
                rb_define_method(cProfile, "stop", prof_stop, 0);
         | 
| 933 918 | 
             
                rb_define_method(cProfile, "resume", prof_resume, 0);
         | 
    
        data/ext/ruby_prof/rp_profile.h
    CHANGED
    
    
    
        data/ext/ruby_prof/rp_thread.c
    CHANGED
    
    | @@ -58,18 +58,18 @@ void prof_thread_mark(void* data) | |
| 58 58 | 
             
                thread_data_t* thread = (thread_data_t*)data;
         | 
| 59 59 |  | 
| 60 60 | 
             
                if (thread->object != Qnil)
         | 
| 61 | 
            -
                     | 
| 61 | 
            +
                    rb_gc_mark_movable(thread->object);
         | 
| 62 62 |  | 
| 63 63 | 
             
                rb_gc_mark(thread->fiber);
         | 
| 64 64 |  | 
| 65 65 | 
             
                if (thread->methods != Qnil)
         | 
| 66 | 
            -
                     | 
| 66 | 
            +
                    rb_gc_mark_movable(thread->methods);
         | 
| 67 67 |  | 
| 68 68 | 
             
                if (thread->fiber_id != Qnil)
         | 
| 69 | 
            -
                     | 
| 69 | 
            +
                    rb_gc_mark_movable(thread->fiber_id);
         | 
| 70 70 |  | 
| 71 71 | 
             
                if (thread->thread_id != Qnil)
         | 
| 72 | 
            -
                     | 
| 72 | 
            +
                    rb_gc_mark_movable(thread->thread_id);
         | 
| 73 73 |  | 
| 74 74 | 
             
                if (thread->call_tree)
         | 
| 75 75 | 
             
                    prof_call_tree_mark(thread->call_tree);
         | 
| @@ -77,6 +77,15 @@ void prof_thread_mark(void* data) | |
| 77 77 | 
             
                rb_st_foreach(thread->method_table, mark_methods, 0);
         | 
| 78 78 | 
             
            }
         | 
| 79 79 |  | 
| 80 | 
            +
            void prof_thread_compact(void* data)
         | 
| 81 | 
            +
            {
         | 
| 82 | 
            +
                thread_data_t* thread = (thread_data_t*)data;
         | 
| 83 | 
            +
                thread->object = rb_gc_location(thread->object);
         | 
| 84 | 
            +
                thread->methods = rb_gc_location(thread->methods);
         | 
| 85 | 
            +
                thread->fiber_id = rb_gc_location(thread->fiber_id);
         | 
| 86 | 
            +
                thread->thread_id = rb_gc_location(thread->thread_id);
         | 
| 87 | 
            +
            }
         | 
| 88 | 
            +
             | 
| 80 89 | 
             
            static void prof_thread_free(thread_data_t* thread_data)
         | 
| 81 90 | 
             
            {
         | 
| 82 91 | 
             
                /* Has this method object been accessed by Ruby?  If
         | 
| @@ -126,6 +135,7 @@ static const rb_data_type_t thread_type = | |
| 126 135 | 
             
                    .dmark = prof_thread_mark,
         | 
| 127 136 | 
             
                    .dfree = prof_thread_ruby_gc_free,
         | 
| 128 137 | 
             
                    .dsize = prof_thread_size,
         | 
| 138 | 
            +
                    .dcompact = prof_thread_compact
         | 
| 129 139 | 
             
                },
         | 
| 130 140 | 
             
                .data = NULL,
         | 
| 131 141 | 
             
                .flags = RUBY_TYPED_FREE_IMMEDIATELY
         | 
| @@ -66,7 +66,7 @@ | |
| 66 66 | 
             
              </PropertyGroup>
         | 
| 67 67 | 
             
              <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
         | 
| 68 68 | 
             
                <TargetExt>.so</TargetExt>
         | 
| 69 | 
            -
                <OutDir>$(SolutionDir) | 
| 69 | 
            +
                <OutDir>$(SolutionDir)\..</OutDir>
         | 
| 70 70 | 
             
              </PropertyGroup>
         | 
| 71 71 | 
             
              <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
         | 
| 72 72 | 
             
                <ClCompile>
         | 
| @@ -96,4 +96,18 @@ module RubyProf | |
| 96 96 | 
             
              def self.ensure_not_running!
         | 
| 97 97 | 
             
                raise(RuntimeError, "RubyProf is already running") if running?
         | 
| 98 98 | 
             
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              class << self
         | 
| 101 | 
            +
                extend Gem::Deprecate
         | 
| 102 | 
            +
                deprecate :measure_mode, "Profile#measure_mode", 2023, 6
         | 
| 103 | 
            +
                deprecate :measure_mode=, "Profile#measure_mode=", 2023, 6
         | 
| 104 | 
            +
                deprecate :exclude_threads, "Profile#exclude_threads", 2023, 6
         | 
| 105 | 
            +
                deprecate :exclude_threads=, "Profile#initialize", 2023, 6
         | 
| 106 | 
            +
                deprecate :start, "Profile#start", 2023, 6
         | 
| 107 | 
            +
                deprecate :pause, "Profile#pause", 2023, 6
         | 
| 108 | 
            +
                deprecate :stop, "Profile#stop", 2023, 6
         | 
| 109 | 
            +
                deprecate :resume, "Profile#resume", 2023, 6
         | 
| 110 | 
            +
                deprecate :running?, "Profile#running?", 2023, 6
         | 
| 111 | 
            +
                deprecate :profile, "Profile.profile", 2023, 6
         | 
| 112 | 
            +
              end
         | 
| 99 113 | 
             
            end
         | 
| @@ -50,7 +50,7 @@ module RubyProf | |
| 50 50 | 
             
                # options - Hash of print options. Note that each printer can
         | 
| 51 51 | 
             
                # define its own set of options.
         | 
| 52 52 | 
             
                #
         | 
| 53 | 
            -
                #   :min_percent - Number 0 to 100 that  | 
| 53 | 
            +
                #   :min_percent - Number 0 to 100 that specifies the minimum
         | 
| 54 54 | 
             
                #                  %self (the methods self time divided by the
         | 
| 55 55 | 
             
                #                  overall total time) that a method must take
         | 
| 56 56 | 
             
                #                  for it to be printed out in the report.
         | 
| @@ -27,7 +27,7 @@ module RubyProf | |
| 27 27 |  | 
| 28 28 | 
             
                def determine_event_specification_and_value_scale
         | 
| 29 29 | 
             
                  @event_specification = "events: "
         | 
| 30 | 
            -
                  case  | 
| 30 | 
            +
                  case @result.measure_mode
         | 
| 31 31 | 
             
                    when RubyProf::PROCESS_TIME
         | 
| 32 32 | 
             
                      @value_scale = RubyProf::CLOCKS_PER_SEC
         | 
| 33 33 | 
             
                      @event_specification << 'process_time'
         | 
| @@ -6,16 +6,16 @@ module RubyProf | |
| 6 6 | 
             
              # profile, a call stack profile and a graph profile.
         | 
| 7 7 | 
             
              class MultiPrinter
         | 
| 8 8 | 
             
                def initialize(result, printers = [:flat, :graph_html])
         | 
| 9 | 
            -
                  @flat_printer = FlatPrinter.new(result)  | 
| 9 | 
            +
                  @flat_printer = printers.include?(:flat) ? FlatPrinter.new(result) : nil
         | 
| 10 10 |  | 
| 11 | 
            -
                  @graph_printer = GraphPrinter.new(result)  | 
| 12 | 
            -
                  @graph_html_printer = GraphHtmlPrinter.new(result)  | 
| 11 | 
            +
                  @graph_printer = printers.include?(:graph) ? GraphPrinter.new(result) : nil
         | 
| 12 | 
            +
                  @graph_html_printer = printers.include?(:graph_html) ? GraphHtmlPrinter.new(result) : nil
         | 
| 13 13 |  | 
| 14 | 
            -
                  @tree_printer = CallTreePrinter.new(result)  | 
| 15 | 
            -
                  @call_info_printer = CallInfoPrinter.new(result)  | 
| 14 | 
            +
                  @tree_printer = printers.include?(:tree) ? CallTreePrinter.new(result) : nil
         | 
| 15 | 
            +
                  @call_info_printer = printers.include?(:call_tree) ? CallInfoPrinter.new(result) : nil
         | 
| 16 16 |  | 
| 17 | 
            -
                  @stack_printer = CallStackPrinter.new(result)  | 
| 18 | 
            -
                  @dot_printer = DotPrinter.new(result)  | 
| 17 | 
            +
                  @stack_printer = printers.include?(:stack) ? CallStackPrinter.new(result) : nil
         | 
| 18 | 
            +
                  @dot_printer = printers.include?(:dot) ? DotPrinter.new(result) : nil
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 21 | 
             
                def self.needs_dir?
         | 
| @@ -28,7 +28,7 @@ module RubyProf | |
| 28 28 | 
             
                def print(options)
         | 
| 29 29 | 
             
                  validate_print_params(options)
         | 
| 30 30 |  | 
| 31 | 
            -
                  @ | 
| 31 | 
            +
                  @file_name = options.delete(:profile) || "profile"
         | 
| 32 32 | 
             
                  @directory = options.delete(:path) || File.expand_path(".")
         | 
| 33 33 |  | 
| 34 34 | 
             
                  print_to_flat(options) if @flat_printer
         | 
| @@ -44,36 +44,36 @@ module RubyProf | |
| 44 44 |  | 
| 45 45 | 
             
                # the name of the flat profile file
         | 
| 46 46 | 
             
                def flat_report
         | 
| 47 | 
            -
                  "#{@directory}/#{@ | 
| 47 | 
            +
                  "#{@directory}/#{@file_name}.flat.txt"
         | 
| 48 48 | 
             
                end
         | 
| 49 49 |  | 
| 50 50 | 
             
                # the name of the graph profile file
         | 
| 51 51 | 
             
                def graph_report
         | 
| 52 | 
            -
                  "#{@directory}/#{@ | 
| 52 | 
            +
                  "#{@directory}/#{@file_name}.graph.txt"
         | 
| 53 53 | 
             
                end
         | 
| 54 54 |  | 
| 55 55 | 
             
                def graph_html_report
         | 
| 56 | 
            -
                  "#{@directory}/#{@ | 
| 56 | 
            +
                  "#{@directory}/#{@file_name}.graph.html"
         | 
| 57 57 | 
             
                end
         | 
| 58 58 |  | 
| 59 59 | 
             
                # the name of the callinfo profile file
         | 
| 60 60 | 
             
                def call_info_report
         | 
| 61 | 
            -
                  "#{@directory}/#{@ | 
| 61 | 
            +
                  "#{@directory}/#{@file_name}.call_tree.txt"
         | 
| 62 62 | 
             
                end
         | 
| 63 63 |  | 
| 64 64 | 
             
                # the name of the callgrind profile file
         | 
| 65 65 | 
             
                def tree_report
         | 
| 66 | 
            -
                  "#{@directory}/#{@ | 
| 66 | 
            +
                  "#{@directory}/#{@file_name}.callgrind.out.#{$$}"
         | 
| 67 67 | 
             
                end
         | 
| 68 68 |  | 
| 69 69 | 
             
                # the name of the call stack profile file
         | 
| 70 70 | 
             
                def stack_report
         | 
| 71 | 
            -
                  "#{@directory}/#{@ | 
| 71 | 
            +
                  "#{@directory}/#{@file_name}.stack.html"
         | 
| 72 72 | 
             
                end
         | 
| 73 73 |  | 
| 74 74 | 
             
                # the name of the call stack profile file
         | 
| 75 75 | 
             
                def dot_report
         | 
| 76 | 
            -
                  "#{@directory}/#{@ | 
| 76 | 
            +
                  "#{@directory}/#{@file_name}.dot"
         | 
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 79 | 
             
                def print_to_flat(options)
         | 
| @@ -101,12 +101,12 @@ module RubyProf | |
| 101 101 | 
             
                end
         | 
| 102 102 |  | 
| 103 103 | 
             
                def print_to_tree(options)
         | 
| 104 | 
            -
                  @tree_printer.print(options.merge(:path => @directory, :profile => @ | 
| 104 | 
            +
                  @tree_printer.print(options.merge(:path => @directory, :profile => @file_name))
         | 
| 105 105 | 
             
                end
         | 
| 106 106 |  | 
| 107 107 | 
             
                def print_to_stack(options)
         | 
| 108 108 | 
             
                  File.open(stack_report, "wb") do |file|
         | 
| 109 | 
            -
                    @stack_printer.print(file, options.merge(:graph => "#{@ | 
| 109 | 
            +
                    @stack_printer.print(file, options.merge(:graph => "#{@file_name}.graph.html"))
         | 
| 110 110 | 
             
                  end
         | 
| 111 111 | 
             
                end
         | 
| 112 112 |  | 
    
        data/lib/ruby-prof/profile.rb
    CHANGED
    
    | @@ -23,14 +23,14 @@ module RubyProf | |
| 23 23 | 
             
                  ExcludeCommonMethods.apply!(self)
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 | 
            -
                def exclude_methods!(mod, * | 
| 27 | 
            -
                  [ | 
| 28 | 
            -
                    exclude_method!(mod,  | 
| 26 | 
            +
                def exclude_methods!(mod, *method_names)
         | 
| 27 | 
            +
                  [method_names].flatten.each do |method_name|
         | 
| 28 | 
            +
                    exclude_method!(mod, method_name)
         | 
| 29 29 | 
             
                  end
         | 
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 | 
            -
                def exclude_singleton_methods!(mod, * | 
| 33 | 
            -
                  exclude_methods!(mod.singleton_class, * | 
| 32 | 
            +
                def exclude_singleton_methods!(mod, *method_names)
         | 
| 33 | 
            +
                  exclude_methods!(mod.singleton_class, *method_names)
         | 
| 34 34 | 
             
                end
         | 
| 35 35 |  | 
| 36 36 | 
             
                # call-seq:
         | 
    
        data/lib/ruby-prof/rack.rb
    CHANGED
    
    | @@ -6,7 +6,6 @@ module Rack | |
| 6 6 | 
             
                def initialize(app, options = {})
         | 
| 7 7 | 
             
                  @app = app
         | 
| 8 8 | 
             
                  @options = options
         | 
| 9 | 
            -
                  @options[:min_percent] ||= 1
         | 
| 10 9 |  | 
| 11 10 | 
             
                  @tmpdir = options[:path] || Dir.tmpdir
         | 
| 12 11 | 
             
                  FileUtils.mkdir_p(@tmpdir)
         | 
| @@ -26,14 +25,19 @@ module Rack | |
| 26 25 | 
             
                  if should_profile?(request.path)
         | 
| 27 26 | 
             
                    begin
         | 
| 28 27 | 
             
                      result = nil
         | 
| 29 | 
            -
                       | 
| 28 | 
            +
                      profile = ::RubyProf::Profile.profile(profiling_options) do
         | 
| 30 29 | 
             
                        result = @app.call(env)
         | 
| 31 30 | 
             
                      end
         | 
| 32 31 |  | 
| 32 | 
            +
                      if @options[:merge_fibers]
         | 
| 33 | 
            +
                        profile.merge!
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
             | 
| 33 37 | 
             
                      path = request.path.gsub('/', '-')
         | 
| 34 38 | 
             
                      path.slice!(0)
         | 
| 35 39 |  | 
| 36 | 
            -
                      print( | 
| 40 | 
            +
                      print(profile, path)
         | 
| 37 41 | 
             
                      result
         | 
| 38 42 | 
             
                    end
         | 
| 39 43 | 
             
                  else
         | 
| @@ -54,39 +58,45 @@ module Rack | |
| 54 58 | 
             
                end
         | 
| 55 59 |  | 
| 56 60 | 
             
                def profiling_options
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
                   | 
| 59 | 
            -
                  options[: | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
                    end
         | 
| 65 | 
            -
                  if @options[:request_thread_only]
         | 
| 66 | 
            -
                    options[:include_threads] = [Thread.current]
         | 
| 61 | 
            +
                  result = {}
         | 
| 62 | 
            +
                  result[:measure_mode] = @options[:measure_mode] || ::RubyProf::WALL_TIME
         | 
| 63 | 
            +
                  result[:track_allocations] = @options[:track_allocations] || false
         | 
| 64 | 
            +
                  result[:exclude_common] = @options[:exclude_common] || false
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  if @options[:ignore_existing_threads]
         | 
| 67 | 
            +
                    result[:exclude_threads] = Thread.list.select {|thread| thread != Thread.current}
         | 
| 67 68 | 
             
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 69 | 
            +
             | 
| 70 | 
            +
                  if @options[:request_thread_only]
         | 
| 71 | 
            +
                    result[:include_threads] = [Thread.current]
         | 
| 70 72 | 
             
                  end
         | 
| 71 | 
            -
             | 
| 73 | 
            +
             | 
| 74 | 
            +
                  result
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def print_options
         | 
| 78 | 
            +
                  result = {}
         | 
| 79 | 
            +
                  result[:min_percent] = @options[:min_percent] || 1
         | 
| 80 | 
            +
                  result[:sort_method] = @options[:sort_method] || :total_time
         | 
| 81 | 
            +
                  result
         | 
| 72 82 | 
             
                end
         | 
| 73 83 |  | 
| 74 | 
            -
                def print( | 
| 84 | 
            +
                def print(profile, path)
         | 
| 75 85 | 
             
                  @printer_klasses.each do |printer_klass, base_name|
         | 
| 76 | 
            -
                    printer = printer_klass.new( | 
| 86 | 
            +
                    printer = printer_klass.new(profile)
         | 
| 77 87 |  | 
| 78 88 | 
             
                    if base_name.respond_to?(:call)
         | 
| 79 89 | 
             
                      base_name = base_name.call
         | 
| 80 90 | 
             
                    end
         | 
| 81 91 |  | 
| 82 92 | 
             
                    if printer_klass == ::RubyProf::MultiPrinter
         | 
| 83 | 
            -
                      printer.print( | 
| 93 | 
            +
                      printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
         | 
| 84 94 | 
             
                    elsif printer_klass == ::RubyProf::CallTreePrinter
         | 
| 85 | 
            -
                      printer.print( | 
| 95 | 
            +
                      printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
         | 
| 86 96 | 
             
                    else
         | 
| 87 97 | 
             
                      file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
         | 
| 88 98 | 
             
                      ::File.open(file_name, 'wb') do |file|
         | 
| 89 | 
            -
                        printer.print(file,  | 
| 99 | 
            +
                        printer.print(file, print_options)
         | 
| 90 100 | 
             
                      end
         | 
| 91 101 | 
             
                    end
         | 
| 92 102 | 
             
                  end
         | 
    
        data/lib/ruby-prof/version.rb
    CHANGED