ruby-prof-danielhoey 0.8.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.
- data/CHANGES +221 -0
 - data/LICENSE +23 -0
 - data/README +432 -0
 - data/Rakefile +158 -0
 - data/bin/ruby-prof +224 -0
 - data/examples/flat.txt +55 -0
 - data/examples/graph.html +823 -0
 - data/examples/graph.txt +170 -0
 - data/ext/ruby_prof/call_tree.c +392 -0
 - data/ext/ruby_prof/call_tree.h +32 -0
 - data/ext/ruby_prof/extconf.rb +40 -0
 - data/ext/ruby_prof/list.c +66 -0
 - data/ext/ruby_prof/list.h +10 -0
 - data/ext/ruby_prof/measure_allocations.h +58 -0
 - data/ext/ruby_prof/measure_cpu_time.h +152 -0
 - data/ext/ruby_prof/measure_gc_runs.h +76 -0
 - data/ext/ruby_prof/measure_gc_time.h +57 -0
 - data/ext/ruby_prof/measure_memory.h +101 -0
 - data/ext/ruby_prof/measure_process_time.h +52 -0
 - data/ext/ruby_prof/measure_wall_time.h +53 -0
 - data/ext/ruby_prof/measurement.h +13 -0
 - data/ext/ruby_prof/mingw/Rakefile +23 -0
 - data/ext/ruby_prof/mingw/build.rake +38 -0
 - data/ext/ruby_prof/ruby_prof.c +1943 -0
 - data/ext/ruby_prof/ruby_prof.h +183 -0
 - data/ext/ruby_prof/version.h +4 -0
 - data/lib/ruby-prof.rb +59 -0
 - data/lib/ruby-prof/abstract_printer.rb +41 -0
 - data/lib/ruby-prof/aggregate_call_info.rb +62 -0
 - data/lib/ruby-prof/call_info.rb +47 -0
 - data/lib/ruby-prof/call_tree/abstract_printer.rb +24 -0
 - data/lib/ruby-prof/call_tree/html_printer.rb +89 -0
 - data/lib/ruby-prof/call_tree/html_printer_output.html.erb +99 -0
 - data/lib/ruby-prof/call_tree/text_printer.rb +28 -0
 - data/lib/ruby-prof/call_tree_printer.rb +84 -0
 - data/lib/ruby-prof/flat_printer.rb +78 -0
 - data/lib/ruby-prof/flat_printer_with_line_numbers.rb +72 -0
 - data/lib/ruby-prof/graph_html_printer.rb +256 -0
 - data/lib/ruby-prof/graph_printer.rb +157 -0
 - data/lib/ruby-prof/method_info.rb +111 -0
 - data/lib/ruby-prof/symbol_to_proc.rb +8 -0
 - data/lib/ruby-prof/task.rb +146 -0
 - data/lib/ruby-prof/test.rb +148 -0
 - data/lib/unprof.rb +8 -0
 - data/rails/environment/profile.rb +24 -0
 - data/rails/example/example_test.rb +9 -0
 - data/rails/profile_test_helper.rb +21 -0
 - data/test/aggregate_test.rb +121 -0
 - data/test/basic_test.rb +290 -0
 - data/test/current_failures_windows +8 -0
 - data/test/do_nothing.rb +0 -0
 - data/test/duplicate_names_test.rb +32 -0
 - data/test/enumerable_test.rb +16 -0
 - data/test/exceptions_test.rb +15 -0
 - data/test/exclude_threads_test.rb +54 -0
 - data/test/exec_test.rb +14 -0
 - data/test/line_number_test.rb +73 -0
 - data/test/measurement_test.rb +121 -0
 - data/test/module_test.rb +54 -0
 - data/test/no_method_class_test.rb +14 -0
 - data/test/prime.rb +58 -0
 - data/test/prime_test.rb +13 -0
 - data/test/printers_test.rb +130 -0
 - data/test/recursive_test.rb +275 -0
 - data/test/ruby-prof-bin +20 -0
 - data/test/singleton_test.rb +37 -0
 - data/test/stack_test.rb +138 -0
 - data/test/start_stop_test.rb +95 -0
 - data/test/test_suite.rb +23 -0
 - data/test/thread_test.rb +173 -0
 - data/test/unique_call_path_test.rb +225 -0
 - metadata +163 -0
 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* :nodoc: 
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Copyright (C) 2008  Alexander Dymo <adymo@pluron.com>
         
     | 
| 
      
 3 
     | 
    
         
            +
             *
         
     | 
| 
      
 4 
     | 
    
         
            +
             * All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
             *
         
     | 
| 
      
 6 
     | 
    
         
            +
             * Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 7 
     | 
    
         
            +
             * modification, are permitted provided that the following conditions
         
     | 
| 
      
 8 
     | 
    
         
            +
             * are met:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 1. Redistributions of source code must retain the above copyright
         
     | 
| 
      
 10 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer.
         
     | 
| 
      
 11 
     | 
    
         
            +
             * 2. Redistributions in binary form must reproduce the above copyright
         
     | 
| 
      
 12 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer in the
         
     | 
| 
      
 13 
     | 
    
         
            +
             *    documentation and/or other materials provided with the distribution.
         
     | 
| 
      
 14 
     | 
    
         
            +
             *
         
     | 
| 
      
 15 
     | 
    
         
            +
             * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
         
     | 
| 
      
 16 
     | 
    
         
            +
             * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 17 
     | 
    
         
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
         
     | 
| 
      
 18 
     | 
    
         
            +
             * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 20 
     | 
    
         
            +
             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
         
     | 
| 
      
 21 
     | 
    
         
            +
             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
         
     | 
| 
      
 22 
     | 
    
         
            +
             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
         
     | 
| 
      
 23 
     | 
    
         
            +
             * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
         
     | 
| 
      
 24 
     | 
    
         
            +
             * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
         
     | 
| 
      
 25 
     | 
    
         
            +
             * SUCH DAMAGE. */
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            #if defined(HAVE_RB_GC_ALLOCATED_SIZE)
         
     | 
| 
      
 29 
     | 
    
         
            +
            #define MEASURE_MEMORY 4
         
     | 
| 
      
 30 
     | 
    
         
            +
            #define TOGGLE_GC_STATS 1
         
     | 
| 
      
 31 
     | 
    
         
            +
             
         
     | 
| 
      
 32 
     | 
    
         
            +
            static prof_measure_t
         
     | 
| 
      
 33 
     | 
    
         
            +
            measure_memory()
         
     | 
| 
      
 34 
     | 
    
         
            +
            {
         
     | 
| 
      
 35 
     | 
    
         
            +
            #if defined(HAVE_LONG_LONG)
         
     | 
| 
      
 36 
     | 
    
         
            +
                return NUM2LL(rb_gc_allocated_size());
         
     | 
| 
      
 37 
     | 
    
         
            +
            #else
         
     | 
| 
      
 38 
     | 
    
         
            +
                return NUM2ULONG(rb_gc_allocated_size());
         
     | 
| 
      
 39 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 40 
     | 
    
         
            +
            }
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            static double
         
     | 
| 
      
 43 
     | 
    
         
            +
            convert_memory(prof_measure_t c)
         
     | 
| 
      
 44 
     | 
    
         
            +
            { 
         
     | 
| 
      
 45 
     | 
    
         
            +
                return (double) c / 1024; 
         
     | 
| 
      
 46 
     | 
    
         
            +
            }
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            /* Document-method: prof_measure_memory
         
     | 
| 
      
 49 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 50 
     | 
    
         
            +
                 measure_memory -> int
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            Returns total allocated memory in bytes.*/
         
     | 
| 
      
 53 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 54 
     | 
    
         
            +
            prof_measure_memory(VALUE self)
         
     | 
| 
      
 55 
     | 
    
         
            +
            {
         
     | 
| 
      
 56 
     | 
    
         
            +
                return rb_gc_allocated_size();
         
     | 
| 
      
 57 
     | 
    
         
            +
            }
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            #elif defined(HAVE_RB_GC_MALLOC_ALLOCATED_SIZE)
         
     | 
| 
      
 60 
     | 
    
         
            +
            #define MEASURE_MEMORY 4
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            static prof_measure_t
         
     | 
| 
      
 63 
     | 
    
         
            +
            measure_memory()
         
     | 
| 
      
 64 
     | 
    
         
            +
            {
         
     | 
| 
      
 65 
     | 
    
         
            +
                return rb_gc_malloc_allocated_size();
         
     | 
| 
      
 66 
     | 
    
         
            +
            }
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            static double
         
     | 
| 
      
 69 
     | 
    
         
            +
            convert_memory(prof_measure_t c)
         
     | 
| 
      
 70 
     | 
    
         
            +
            {
         
     | 
| 
      
 71 
     | 
    
         
            +
                return (double) c / 1024;
         
     | 
| 
      
 72 
     | 
    
         
            +
            }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 75 
     | 
    
         
            +
            prof_measure_memory(VALUE self)
         
     | 
| 
      
 76 
     | 
    
         
            +
            {
         
     | 
| 
      
 77 
     | 
    
         
            +
                return UINT2NUM(rb_gc_malloc_allocated_size());
         
     | 
| 
      
 78 
     | 
    
         
            +
            }
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            #elif defined(HAVE_RB_HEAP_TOTAL_MEM)
         
     | 
| 
      
 81 
     | 
    
         
            +
            #define MEASURE_MEMORY 4
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            static prof_measure_t
         
     | 
| 
      
 84 
     | 
    
         
            +
            measure_memory()
         
     | 
| 
      
 85 
     | 
    
         
            +
            {
         
     | 
| 
      
 86 
     | 
    
         
            +
                return rb_heap_total_mem();
         
     | 
| 
      
 87 
     | 
    
         
            +
            }
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            static double
         
     | 
| 
      
 90 
     | 
    
         
            +
            convert_memory(prof_measure_t c)
         
     | 
| 
      
 91 
     | 
    
         
            +
            {
         
     | 
| 
      
 92 
     | 
    
         
            +
                return (double) c / 1024;
         
     | 
| 
      
 93 
     | 
    
         
            +
            }
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 96 
     | 
    
         
            +
            prof_measure_memory(VALUE self)
         
     | 
| 
      
 97 
     | 
    
         
            +
            {
         
     | 
| 
      
 98 
     | 
    
         
            +
                return ULONG2NUM(rb_heap_total_mem());
         
     | 
| 
      
 99 
     | 
    
         
            +
            }
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            #endif
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Copyright (C) 2008  Shugo Maeda <shugo@ruby-lang.org>
         
     | 
| 
      
 3 
     | 
    
         
            +
             *                     Charlie Savage <cfis@savagexi.com>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
             *
         
     | 
| 
      
 6 
     | 
    
         
            +
             * Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 7 
     | 
    
         
            +
             * modification, are permitted provided that the following conditions
         
     | 
| 
      
 8 
     | 
    
         
            +
             * are met:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 1. Redistributions of source code must retain the above copyright
         
     | 
| 
      
 10 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer.
         
     | 
| 
      
 11 
     | 
    
         
            +
             * 2. Redistributions in binary form must reproduce the above copyright
         
     | 
| 
      
 12 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer in the
         
     | 
| 
      
 13 
     | 
    
         
            +
             *    documentation and/or other materials provided with the distribution.
         
     | 
| 
      
 14 
     | 
    
         
            +
             *
         
     | 
| 
      
 15 
     | 
    
         
            +
             * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
         
     | 
| 
      
 16 
     | 
    
         
            +
             * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 17 
     | 
    
         
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
         
     | 
| 
      
 18 
     | 
    
         
            +
             * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 20 
     | 
    
         
            +
             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
         
     | 
| 
      
 21 
     | 
    
         
            +
             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
         
     | 
| 
      
 22 
     | 
    
         
            +
             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
         
     | 
| 
      
 23 
     | 
    
         
            +
             * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
         
     | 
| 
      
 24 
     | 
    
         
            +
             * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
         
     | 
| 
      
 25 
     | 
    
         
            +
             * SUCH DAMAGE. */
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            #include <time.h>
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            #define MEASURE_PROCESS_TIME 0
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            static prof_measure_t
         
     | 
| 
      
 32 
     | 
    
         
            +
            measure_process_time()
         
     | 
| 
      
 33 
     | 
    
         
            +
            {
         
     | 
| 
      
 34 
     | 
    
         
            +
                return clock();
         
     | 
| 
      
 35 
     | 
    
         
            +
            }
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            static double
         
     | 
| 
      
 38 
     | 
    
         
            +
            convert_process_time(prof_measure_t c)
         
     | 
| 
      
 39 
     | 
    
         
            +
            {
         
     | 
| 
      
 40 
     | 
    
         
            +
                return (double) c / CLOCKS_PER_SEC;
         
     | 
| 
      
 41 
     | 
    
         
            +
            }
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            /* Document-method: measure_process_time
         
     | 
| 
      
 44 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 45 
     | 
    
         
            +
                 measure_process_time -> float
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            Returns the process time.*/
         
     | 
| 
      
 48 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 49 
     | 
    
         
            +
            prof_measure_process_time(VALUE self)
         
     | 
| 
      
 50 
     | 
    
         
            +
            {
         
     | 
| 
      
 51 
     | 
    
         
            +
                return rb_float_new(convert_process_time(measure_process_time()));
         
     | 
| 
      
 52 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* :nodoc: 
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Copyright (C) 2008  Shugo Maeda <shugo@ruby-lang.org>
         
     | 
| 
      
 3 
     | 
    
         
            +
             *                     Charlie Savage <cfis@savagexi.com>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
             *
         
     | 
| 
      
 6 
     | 
    
         
            +
             * Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 7 
     | 
    
         
            +
             * modification, are permitted provided that the following conditions
         
     | 
| 
      
 8 
     | 
    
         
            +
             * are met:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 1. Redistributions of source code must retain the above copyright
         
     | 
| 
      
 10 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer.
         
     | 
| 
      
 11 
     | 
    
         
            +
             * 2. Redistributions in binary form must reproduce the above copyright
         
     | 
| 
      
 12 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer in the
         
     | 
| 
      
 13 
     | 
    
         
            +
             *    documentation and/or other materials provided with the distribution.
         
     | 
| 
      
 14 
     | 
    
         
            +
             *
         
     | 
| 
      
 15 
     | 
    
         
            +
             * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
         
     | 
| 
      
 16 
     | 
    
         
            +
             * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 17 
     | 
    
         
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
         
     | 
| 
      
 18 
     | 
    
         
            +
             * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 20 
     | 
    
         
            +
             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
         
     | 
| 
      
 21 
     | 
    
         
            +
             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
         
     | 
| 
      
 22 
     | 
    
         
            +
             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
         
     | 
| 
      
 23 
     | 
    
         
            +
             * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
         
     | 
| 
      
 24 
     | 
    
         
            +
             * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
         
     | 
| 
      
 25 
     | 
    
         
            +
             * SUCH DAMAGE. */
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            #define MEASURE_WALL_TIME 1
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            static prof_measure_t
         
     | 
| 
      
 31 
     | 
    
         
            +
            measure_wall_time()
         
     | 
| 
      
 32 
     | 
    
         
            +
            {
         
     | 
| 
      
 33 
     | 
    
         
            +
                struct timeval tv;
         
     | 
| 
      
 34 
     | 
    
         
            +
                gettimeofday(&tv, NULL);
         
     | 
| 
      
 35 
     | 
    
         
            +
                return tv.tv_sec * 1000000 + tv.tv_usec;
         
     | 
| 
      
 36 
     | 
    
         
            +
            }
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            static double
         
     | 
| 
      
 39 
     | 
    
         
            +
            convert_wall_time(prof_measure_t c)
         
     | 
| 
      
 40 
     | 
    
         
            +
            {
         
     | 
| 
      
 41 
     | 
    
         
            +
                return (double) c / 1000000;
         
     | 
| 
      
 42 
     | 
    
         
            +
            }
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            /* Document-method: prof_measure_wall_time
         
     | 
| 
      
 45 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 46 
     | 
    
         
            +
                 measure_wall_time -> float
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            Returns the wall time.*/
         
     | 
| 
      
 49 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 50 
     | 
    
         
            +
            prof_measure_wall_time(VALUE self)
         
     | 
| 
      
 51 
     | 
    
         
            +
            {
         
     | 
| 
      
 52 
     | 
    
         
            +
                return rb_float_new(convert_wall_time(measure_wall_time()));
         
     | 
| 
      
 53 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #ifndef MEASUREMENT
         
     | 
| 
      
 2 
     | 
    
         
            +
            #define MEASUREMENT
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            #ifdef HAVE_LONG_LONG
         
     | 
| 
      
 5 
     | 
    
         
            +
            typedef unsigned LONG_LONG prof_measure_t; // long long is 8 bytes on 32-bit
         
     | 
| 
      
 6 
     | 
    
         
            +
            #else
         
     | 
| 
      
 7 
     | 
    
         
            +
            typedef unsigned long prof_measure_t;
         
     | 
| 
      
 8 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            extern prof_measure_t (*get_measurement)();
         
     | 
| 
      
 11 
     | 
    
         
            +
            extern double (*convert_measurement)(prof_measure_t);
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            #endif
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # We can't use Ruby's standard build procedures
         
     | 
| 
      
 2 
     | 
    
         
            +
            # on Windows because the Ruby executable is
         
     | 
| 
      
 3 
     | 
    
         
            +
            # built with VC++ while here we want to build
         
     | 
| 
      
 4 
     | 
    
         
            +
            # with MingW.  So just roll our own...
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'rbconfig'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            EXTENSION_NAME = "ruby_prof.#{Config::CONFIG["DLEXT"]}"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # This is called when the Windows GEM is installed!
         
     | 
| 
      
 12 
     | 
    
         
            +
            task :install do
         
     | 
| 
      
 13 
     | 
    
         
            +
              # Gems will pass these two environment variables:
         
     | 
| 
      
 14 
     | 
    
         
            +
              # RUBYARCHDIR=#{dest_path}
         
     | 
| 
      
 15 
     | 
    
         
            +
              # RUBYLIBDIR=#{dest_path}
         
     | 
| 
      
 16 
     | 
    
         
            +
              
         
     | 
| 
      
 17 
     | 
    
         
            +
              dest_path = ENV['RUBYLIBDIR']
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              # Copy the extension
         
     | 
| 
      
 20 
     | 
    
         
            +
              cp(EXTENSION_NAME, dest_path)
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            task :default => :install
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # We can't use Ruby's standard build procedures
         
     | 
| 
      
 2 
     | 
    
         
            +
            # on Windows because the Ruby executable is
         
     | 
| 
      
 3 
     | 
    
         
            +
            # built with VC++ while here we want to build
         
     | 
| 
      
 4 
     | 
    
         
            +
            # with MingW.  So just roll our own...
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'rake/clean'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'rbconfig'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            RUBY_INCLUDE_DIR = Config::CONFIG["archdir"]
         
     | 
| 
      
 10 
     | 
    
         
            +
            RUBY_BIN_DIR = Config::CONFIG["bindir"]
         
     | 
| 
      
 11 
     | 
    
         
            +
            RUBY_LIB_DIR = Config::CONFIG["libdir"]
         
     | 
| 
      
 12 
     | 
    
         
            +
            RUBY_SHARED_LIB = Config::CONFIG["LIBRUBY"]
         
     | 
| 
      
 13 
     | 
    
         
            +
            RUBY_SHARED_DLL = RUBY_SHARED_LIB.gsub(/lib$/, 'dll')
         
     | 
| 
      
 14 
     | 
    
         
            +
                
         
     | 
| 
      
 15 
     | 
    
         
            +
            EXTENSION_NAME = "ruby_prof.#{Config::CONFIG["DLEXT"]}"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            CLEAN.include('*.o')
         
     | 
| 
      
 18 
     | 
    
         
            +
            CLOBBER.include(EXTENSION_NAME)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            task :default => "ruby_prof"
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            SRC = FileList['../*.c']
         
     | 
| 
      
 23 
     | 
    
         
            +
            OBJ = SRC.collect do |file_name|
         
     | 
| 
      
 24 
     | 
    
         
            +
              File.basename(file_name).ext('o')
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            SRC.each do |srcfile|
         
     | 
| 
      
 28 
     | 
    
         
            +
              objfile = File.basename(srcfile).ext('o')
         
     | 
| 
      
 29 
     | 
    
         
            +
              file objfile => srcfile do
         
     | 
| 
      
 30 
     | 
    
         
            +
                command = "gcc -c -fPIC -O2 -Wall -o #{objfile} -I/usr/local/include #{srcfile} -I#{RUBY_INCLUDE_DIR}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                sh "sh -c '#{command}'" 
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            file "ruby_prof" => OBJ do
         
     | 
| 
      
 36 
     | 
    
         
            +
              command = "gcc -shared -o #{EXTENSION_NAME} -L/usr/local/lib #{OBJ} #{RUBY_BIN_DIR}/#{RUBY_SHARED_DLL}" 
         
     | 
| 
      
 37 
     | 
    
         
            +
              sh "sh -c '#{command}'" 
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,1943 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*
         
     | 
| 
      
 2 
     | 
    
         
            +
             * Copyright (C) 2008  Shugo Maeda <shugo@ruby-lang.org>
         
     | 
| 
      
 3 
     | 
    
         
            +
             *                     Charlie Savage <cfis@savagexi.com>
         
     | 
| 
      
 4 
     | 
    
         
            +
             * All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
             *
         
     | 
| 
      
 6 
     | 
    
         
            +
             * Redistribution and use in source and binary forms, with or without
         
     | 
| 
      
 7 
     | 
    
         
            +
             * modification, are permitted provided that the following conditions
         
     | 
| 
      
 8 
     | 
    
         
            +
             * are met:
         
     | 
| 
      
 9 
     | 
    
         
            +
             * 1. Redistributions of source code must retain the above copyright
         
     | 
| 
      
 10 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer.
         
     | 
| 
      
 11 
     | 
    
         
            +
             * 2. Redistributions in binary form must reproduce the above copyright
         
     | 
| 
      
 12 
     | 
    
         
            +
             *    notice, this list of conditions and the following disclaimer in the
         
     | 
| 
      
 13 
     | 
    
         
            +
             *    documentation and/or other materials provided with the distribution.
         
     | 
| 
      
 14 
     | 
    
         
            +
             *
         
     | 
| 
      
 15 
     | 
    
         
            +
             * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
         
     | 
| 
      
 16 
     | 
    
         
            +
             * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         
     | 
| 
      
 17 
     | 
    
         
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
         
     | 
| 
      
 18 
     | 
    
         
            +
             * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
         
     | 
| 
      
 19 
     | 
    
         
            +
             * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         
     | 
| 
      
 20 
     | 
    
         
            +
             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
         
     | 
| 
      
 21 
     | 
    
         
            +
             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
         
     | 
| 
      
 22 
     | 
    
         
            +
             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
         
     | 
| 
      
 23 
     | 
    
         
            +
             * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
         
     | 
| 
      
 24 
     | 
    
         
            +
             * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
         
     | 
| 
      
 25 
     | 
    
         
            +
             * SUCH DAMAGE.
         
     | 
| 
      
 26 
     | 
    
         
            +
             */
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            /* ruby-prof tracks the time spent executing every method in ruby programming.
         
     | 
| 
      
 29 
     | 
    
         
            +
               The main players are:
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                 prof_result_t     - Its one field, values,  contains the overall results
         
     | 
| 
      
 32 
     | 
    
         
            +
                 thread_data_t     - Stores data about a single thread.  
         
     | 
| 
      
 33 
     | 
    
         
            +
                 prof_stack_t      - The method call stack in a particular thread
         
     | 
| 
      
 34 
     | 
    
         
            +
                 prof_method_t     - Profiling information for each method
         
     | 
| 
      
 35 
     | 
    
         
            +
                 prof_call_info_t  - Keeps track a method's callers and callees. 
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              The final resulut is a hash table of thread_data_t, keyed on the thread
         
     | 
| 
      
 38 
     | 
    
         
            +
              id.  Each thread has an hash a table of prof_method_t, keyed on the
         
     | 
| 
      
 39 
     | 
    
         
            +
              method id.  A hash table is used for quick look up when doing a profile.
         
     | 
| 
      
 40 
     | 
    
         
            +
              However, it is exposed to Ruby as an array.
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              Each prof_method_t has two hash tables, parent and children, of prof_call_info_t.
         
     | 
| 
      
 43 
     | 
    
         
            +
              These objects keep track of a method's callers (who called the method) and its
         
     | 
| 
      
 44 
     | 
    
         
            +
              callees (who the method called).  These are keyed the method id, but once again,
         
     | 
| 
      
 45 
     | 
    
         
            +
              are exposed to Ruby as arrays.  Each prof_call_into_t maintains a pointer to the
         
     | 
| 
      
 46 
     | 
    
         
            +
              caller or callee method, thereby making it easy to navigate through the call 
         
     | 
| 
      
 47 
     | 
    
         
            +
              hierarchy in ruby - which is very helpful for creating call graphs.      
         
     | 
| 
      
 48 
     | 
    
         
            +
            */
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            #include "ruby_prof.h"
         
     | 
| 
      
 51 
     | 
    
         
            +
            #include <stdio.h>
         
     | 
| 
      
 52 
     | 
    
         
            +
            #include <assert.h>
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            #include "call_tree.h"
         
     | 
| 
      
 56 
     | 
    
         
            +
            static int call_tree_profile_on = 1;
         
     | 
| 
      
 57 
     | 
    
         
            +
            static VALUE call_tree_top_level;
         
     | 
| 
      
 58 
     | 
    
         
            +
            static VALUE call_tree_current_call;
         
     | 
| 
      
 59 
     | 
    
         
            +
            static st_table* threads;
         
     | 
| 
      
 60 
     | 
    
         
            +
            static VALUE call_tree_last_thread_id = Qnil;
         
     | 
| 
      
 61 
     | 
    
         
            +
            static VALUE thread;
         
     | 
| 
      
 62 
     | 
    
         
            +
            static VALUE call_tree_thread_id;
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            static VALUE klass_name(VALUE klass);
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            static size_t store_method_against_thread(VALUE thread_id, VALUE call_tree_method)
         
     | 
| 
      
 67 
     | 
    
         
            +
            {
         
     | 
| 
      
 68 
     | 
    
         
            +
                /* Its too slow to key on the real thread id so just typecast thread instead. */
         
     | 
| 
      
 69 
     | 
    
         
            +
                return st_insert(threads, (st_data_t) thread_id, (st_data_t) call_tree_method);
         
     | 
| 
      
 70 
     | 
    
         
            +
            }
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            static VALUE lookup_thread(VALUE thread_id)
         
     | 
| 
      
 73 
     | 
    
         
            +
            {
         
     | 
| 
      
 74 
     | 
    
         
            +
                st_data_t val;
         
     | 
| 
      
 75 
     | 
    
         
            +
                if (st_lookup(threads, (st_data_t) thread_id, &val))
         
     | 
| 
      
 76 
     | 
    
         
            +
                {
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return (VALUE) val;
         
     | 
| 
      
 78 
     | 
    
         
            +
                }
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
                return Qnil;
         
     | 
| 
      
 81 
     | 
    
         
            +
            }
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            static void call_tree_prof_event_hook(rb_event_flag_t event, NODE* node, VALUE self, ID mid, VALUE klass)
         
     | 
| 
      
 86 
     | 
    
         
            +
            {
         
     | 
| 
      
 87 
     | 
    
         
            +
                if (self == mProf) return; // skip any methods from the mProf 
         
     | 
| 
      
 88 
     | 
    
         
            +
                if (mid == 1) return;
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                prof_measure_t now = get_measurement();  // Get current measurement    
         
     | 
| 
      
 91 
     | 
    
         
            +
                VALUE call_tree_thread = rb_thread_current();
         
     | 
| 
      
 92 
     | 
    
         
            +
                call_tree_thread_id = rb_obj_id(call_tree_thread);
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
             // Get the current thread information.
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
               # ifdef RUBY_VM
         
     | 
| 
      
 97 
     | 
    
         
            +
                 /* ensure that new threads are hooked [sigh] (bug in core) */
         
     | 
| 
      
 98 
     | 
    
         
            +
                 // just do this on a context switch?
         
     | 
| 
      
 99 
     | 
    
         
            +
                 prof_remove_hook();
         
     | 
| 
      
 100 
     | 
    
         
            +
                 prof_install_hook();
         
     | 
| 
      
 101 
     | 
    
         
            +
               # endif  
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                /* Was there a context switch? */
         
     | 
| 
      
 104 
     | 
    
         
            +
                VALUE call_tree_switched_call = Qnil;
         
     | 
| 
      
 105 
     | 
    
         
            +
                int call_tree_new_thread = 0;
         
     | 
| 
      
 106 
     | 
    
         
            +
              
         
     | 
| 
      
 107 
     | 
    
         
            +
                if (call_tree_last_thread_id != call_tree_thread_id)  
         
     | 
| 
      
 108 
     | 
    
         
            +
                {
         
     | 
| 
      
 109 
     | 
    
         
            +
                    call_tree_switched_call = lookup_thread(call_tree_thread_id);
         
     | 
| 
      
 110 
     | 
    
         
            +
                    call_tree_new_thread = NIL_P(call_tree_switched_call);
         
     | 
| 
      
 111 
     | 
    
         
            +
                    call_tree_last_thread_id = call_tree_thread_id;
         
     | 
| 
      
 112 
     | 
    
         
            +
                }
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                if (!NIL_P(call_tree_switched_call)) 
         
     | 
| 
      
 115 
     | 
    
         
            +
                {
         
     | 
| 
      
 116 
     | 
    
         
            +
                   call_tree_method_pause(call_tree_current_call, now);
         
     | 
| 
      
 117 
     | 
    
         
            +
                   call_tree_method_resume(call_tree_switched_call, now);
         
     | 
| 
      
 118 
     | 
    
         
            +
                   call_tree_current_call = call_tree_switched_call;
         
     | 
| 
      
 119 
     | 
    
         
            +
                }
         
     | 
| 
      
 120 
     | 
    
         
            +
                else if (call_tree_new_thread)
         
     | 
| 
      
 121 
     | 
    
         
            +
                {
         
     | 
| 
      
 122 
     | 
    
         
            +
                    call_tree_method_pause(call_tree_current_call, now);
         
     | 
| 
      
 123 
     | 
    
         
            +
                    char thread_id_str[32];
         
     | 
| 
      
 124 
     | 
    
         
            +
                    sprintf(thread_id_str, "%2u", (unsigned int) call_tree_thread_id);
         
     | 
| 
      
 125 
     | 
    
         
            +
                    call_tree_current_call = call_tree_create_thread(call_tree_current_call, thread_id_str, rb_sourcefile(), now);
         
     | 
| 
      
 126 
     | 
    
         
            +
                }
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                prof_remove_hook();
         
     | 
| 
      
 129 
     | 
    
         
            +
                switch (event) {
         
     | 
| 
      
 130 
     | 
    
         
            +
                  case RUBY_EVENT_CALL:
         
     | 
| 
      
 131 
     | 
    
         
            +
                  case RUBY_EVENT_C_CALL:
         
     | 
| 
      
 132 
     | 
    
         
            +
                  {
         
     | 
| 
      
 133 
     | 
    
         
            +
                      if (klass != 0 && BUILTIN_TYPE(klass) == T_ICLASS)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      {
         
     | 
| 
      
 135 
     | 
    
         
            +
                          klass = RBASIC(klass)->klass;
         
     | 
| 
      
 136 
     | 
    
         
            +
                      }
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                      call_tree_current_call = call_tree_method_start(call_tree_current_call, klass_name(klass), mid, rb_sourcefile(), now);
         
     | 
| 
      
 139 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 140 
     | 
    
         
            +
                  }
         
     | 
| 
      
 141 
     | 
    
         
            +
                  case RUBY_EVENT_RETURN:
         
     | 
| 
      
 142 
     | 
    
         
            +
                  case RUBY_EVENT_C_RETURN:
         
     | 
| 
      
 143 
     | 
    
         
            +
                  {       
         
     | 
| 
      
 144 
     | 
    
         
            +
                      if (call_tree_current_call != call_tree_top_level) 
         
     | 
| 
      
 145 
     | 
    
         
            +
                      {
         
     | 
| 
      
 146 
     | 
    
         
            +
                        call_tree_current_call = call_tree_method_stop(call_tree_current_call, now);
         
     | 
| 
      
 147 
     | 
    
         
            +
                      }
         
     | 
| 
      
 148 
     | 
    
         
            +
                      break;
         
     | 
| 
      
 149 
     | 
    
         
            +
                  }
         
     | 
| 
      
 150 
     | 
    
         
            +
               }
         
     | 
| 
      
 151 
     | 
    
         
            +
               store_method_against_thread(call_tree_thread_id, call_tree_current_call);      
         
     | 
| 
      
 152 
     | 
    
         
            +
               prof_install_hook();
         
     | 
| 
      
 153 
     | 
    
         
            +
            }
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            static VALUE call_tree_prof_start(VALUE self)
         
     | 
| 
      
 156 
     | 
    
         
            +
            {
         
     | 
| 
      
 157 
     | 
    
         
            +
                threads = st_init_numtable();
         
     | 
| 
      
 158 
     | 
    
         
            +
                VALUE call_tree_thread = rb_thread_current();
         
     | 
| 
      
 159 
     | 
    
         
            +
                call_tree_thread_id = rb_obj_id(call_tree_thread);
         
     | 
| 
      
 160 
     | 
    
         
            +
                store_method_against_thread(call_tree_thread_id, call_tree_current_call);
         
     | 
| 
      
 161 
     | 
    
         
            +
                call_tree_last_thread_id = call_tree_thread_id;    
         
     | 
| 
      
 162 
     | 
    
         
            +
                call_tree_top_level = call_tree_create_root();
         
     | 
| 
      
 163 
     | 
    
         
            +
                prof_measure_t now = get_measurement();
         
     | 
| 
      
 164 
     | 
    
         
            +
                call_tree_top_level = call_tree_method_start(call_tree_top_level, rb_str_new2(""), rb_str_new2(""), "", now);
         
     | 
| 
      
 165 
     | 
    
         
            +
                call_tree_current_call = call_tree_top_level;
         
     | 
| 
      
 166 
     | 
    
         
            +
            }
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            static int stop_thread(st_data_t key, st_data_t value, st_data_t now_arg)
         
     | 
| 
      
 170 
     | 
    
         
            +
            {
         
     | 
| 
      
 171 
     | 
    
         
            +
                VALUE thread_id = (VALUE)key;
         
     | 
| 
      
 172 
     | 
    
         
            +
                VALUE call_tree_method = (VALUE) value;
         
     | 
| 
      
 173 
     | 
    
         
            +
                prof_measure_t now = *(prof_measure_t*) now_arg;
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                while (call_tree_method != call_tree_top_level)
         
     | 
| 
      
 176 
     | 
    
         
            +
                {
         
     | 
| 
      
 177 
     | 
    
         
            +
                   call_tree_method = call_tree_method_stop(call_tree_method, now);
         
     | 
| 
      
 178 
     | 
    
         
            +
                } 
         
     | 
| 
      
 179 
     | 
    
         
            +
                return 0;
         
     | 
| 
      
 180 
     | 
    
         
            +
            }
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
            static VALUE call_tree_prof_stop(VALUE self)
         
     | 
| 
      
 183 
     | 
    
         
            +
            {
         
     | 
| 
      
 184 
     | 
    
         
            +
                prof_measure_t now = get_measurement();
         
     | 
| 
      
 185 
     | 
    
         
            +
                st_foreach(threads,  stop_thread, (st_data_t) &now);
         
     | 
| 
      
 186 
     | 
    
         
            +
                call_tree_method_stop(call_tree_top_level, now);
         
     | 
| 
      
 187 
     | 
    
         
            +
                st_free_table(threads);
         
     | 
| 
      
 188 
     | 
    
         
            +
                return call_tree_top_level;
         
     | 
| 
      
 189 
     | 
    
         
            +
            }
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 193 
     | 
    
         
            +
               call_tree_profile_on -> boolean
         
     | 
| 
      
 194 
     | 
    
         
            +
               
         
     | 
| 
      
 195 
     | 
    
         
            +
               Returns whether ruby-prof is recording the full call tree information */
         
     | 
| 
      
 196 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 197 
     | 
    
         
            +
            prof_get_call_tree_profile_on(VALUE self)
         
     | 
| 
      
 198 
     | 
    
         
            +
            {
         
     | 
| 
      
 199 
     | 
    
         
            +
               if (call_tree_profile_on) { return Qtrue; }
         
     | 
| 
      
 200 
     | 
    
         
            +
               else                      { return Qfalse;}
         
     | 
| 
      
 201 
     | 
    
         
            +
            }
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 204 
     | 
    
         
            +
               call_tree_profile_on -> boolean
         
     | 
| 
      
 205 
     | 
    
         
            +
               
         
     | 
| 
      
 206 
     | 
    
         
            +
               Returns whether ruby-prof is recording the full call tree information */
         
     | 
| 
      
 207 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 208 
     | 
    
         
            +
            prof_set_call_tree_profile_on(VALUE self, VALUE val)
         
     | 
| 
      
 209 
     | 
    
         
            +
            {
         
     | 
| 
      
 210 
     | 
    
         
            +
                if (threads_tbl)
         
     | 
| 
      
 211 
     | 
    
         
            +
                {
         
     | 
| 
      
 212 
     | 
    
         
            +
                  rb_raise(rb_eRuntimeError, "can't set call_tree_profile while profiling");
         
     | 
| 
      
 213 
     | 
    
         
            +
                }
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                call_tree_profile_on = RTEST(val);
         
     | 
| 
      
 216 
     | 
    
         
            +
                return val;
         
     | 
| 
      
 217 
     | 
    
         
            +
            }
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            /* ================  Helper Functions  =================*/
         
     | 
| 
      
 223 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 224 
     | 
    
         
            +
            figure_singleton_name(VALUE klass)
         
     | 
| 
      
 225 
     | 
    
         
            +
            {
         
     | 
| 
      
 226 
     | 
    
         
            +
                VALUE result = Qnil;
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                /* We have come across a singleton object. First
         
     | 
| 
      
 229 
     | 
    
         
            +
                   figure out what it is attached to.*/
         
     | 
| 
      
 230 
     | 
    
         
            +
                VALUE attached = rb_iv_get(klass, "__attached__");
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                /* Is this a singleton class acting as a metaclass? */
         
     | 
| 
      
 233 
     | 
    
         
            +
                if (BUILTIN_TYPE(attached) == T_CLASS)
         
     | 
| 
      
 234 
     | 
    
         
            +
                {
         
     | 
| 
      
 235 
     | 
    
         
            +
                    result = rb_str_new2("<Class::");
         
     | 
| 
      
 236 
     | 
    
         
            +
                    rb_str_append(result, rb_inspect(attached));
         
     | 
| 
      
 237 
     | 
    
         
            +
                    rb_str_cat2(result, ">");
         
     | 
| 
      
 238 
     | 
    
         
            +
                }
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                /* Is this for singleton methods on a module? */
         
     | 
| 
      
 241 
     | 
    
         
            +
                else if (BUILTIN_TYPE(attached) == T_MODULE)
         
     | 
| 
      
 242 
     | 
    
         
            +
                {
         
     | 
| 
      
 243 
     | 
    
         
            +
                    result = rb_str_new2("<Module::");
         
     | 
| 
      
 244 
     | 
    
         
            +
                    rb_str_append(result, rb_inspect(attached));
         
     | 
| 
      
 245 
     | 
    
         
            +
                    rb_str_cat2(result, ">");
         
     | 
| 
      
 246 
     | 
    
         
            +
                }
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                /* Is this for singleton methods on an object? */
         
     | 
| 
      
 249 
     | 
    
         
            +
                else if (BUILTIN_TYPE(attached) == T_OBJECT)
         
     | 
| 
      
 250 
     | 
    
         
            +
                {
         
     | 
| 
      
 251 
     | 
    
         
            +
                    /* Make sure to get the super class so that we don't
         
     | 
| 
      
 252 
     | 
    
         
            +
                       mistakenly grab a T_ICLASS which would lead to
         
     | 
| 
      
 253 
     | 
    
         
            +
                       unknown method errors. */
         
     | 
| 
      
 254 
     | 
    
         
            +
            #ifdef RCLASS_SUPER
         
     | 
| 
      
 255 
     | 
    
         
            +
                    VALUE super = rb_class_real(RCLASS_SUPER(klass));
         
     | 
| 
      
 256 
     | 
    
         
            +
            #else
         
     | 
| 
      
 257 
     | 
    
         
            +
                    VALUE super = rb_class_real(RCLASS(klass)->super);
         
     | 
| 
      
 258 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 259 
     | 
    
         
            +
                    result = rb_str_new2("<Object::");
         
     | 
| 
      
 260 
     | 
    
         
            +
                    rb_str_append(result, rb_inspect(super));
         
     | 
| 
      
 261 
     | 
    
         
            +
                    rb_str_cat2(result, ">");
         
     | 
| 
      
 262 
     | 
    
         
            +
                }
         
     | 
| 
      
 263 
     | 
    
         
            +
                
         
     | 
| 
      
 264 
     | 
    
         
            +
                /* Ok, this could be other things like an array made put onto
         
     | 
| 
      
 265 
     | 
    
         
            +
                   a singleton object (yeah, it happens, see the singleton
         
     | 
| 
      
 266 
     | 
    
         
            +
                   objects test case). */
         
     | 
| 
      
 267 
     | 
    
         
            +
                else
         
     | 
| 
      
 268 
     | 
    
         
            +
                {
         
     | 
| 
      
 269 
     | 
    
         
            +
                    result = rb_inspect(klass);
         
     | 
| 
      
 270 
     | 
    
         
            +
                }
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 273 
     | 
    
         
            +
            }
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 276 
     | 
    
         
            +
            klass_name(VALUE klass)
         
     | 
| 
      
 277 
     | 
    
         
            +
            {
         
     | 
| 
      
 278 
     | 
    
         
            +
                VALUE result = Qnil;
         
     | 
| 
      
 279 
     | 
    
         
            +
                
         
     | 
| 
      
 280 
     | 
    
         
            +
                if (klass == 0 || klass == Qnil)
         
     | 
| 
      
 281 
     | 
    
         
            +
                {
         
     | 
| 
      
 282 
     | 
    
         
            +
                    result = rb_str_new2("Global");
         
     | 
| 
      
 283 
     | 
    
         
            +
                }
         
     | 
| 
      
 284 
     | 
    
         
            +
                else if (BUILTIN_TYPE(klass) == T_MODULE)
         
     | 
| 
      
 285 
     | 
    
         
            +
                {
         
     | 
| 
      
 286 
     | 
    
         
            +
                    result = rb_inspect(klass);
         
     | 
| 
      
 287 
     | 
    
         
            +
                }
         
     | 
| 
      
 288 
     | 
    
         
            +
                else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
         
     | 
| 
      
 289 
     | 
    
         
            +
                {
         
     | 
| 
      
 290 
     | 
    
         
            +
                    result = figure_singleton_name(klass);
         
     | 
| 
      
 291 
     | 
    
         
            +
                }
         
     | 
| 
      
 292 
     | 
    
         
            +
                else if (BUILTIN_TYPE(klass) == T_CLASS)
         
     | 
| 
      
 293 
     | 
    
         
            +
                {
         
     | 
| 
      
 294 
     | 
    
         
            +
                    result = rb_inspect(klass);
         
     | 
| 
      
 295 
     | 
    
         
            +
                }
         
     | 
| 
      
 296 
     | 
    
         
            +
                else
         
     | 
| 
      
 297 
     | 
    
         
            +
                {
         
     | 
| 
      
 298 
     | 
    
         
            +
                    /* Should never happen. */
         
     | 
| 
      
 299 
     | 
    
         
            +
                    result = rb_str_new2("Unknown");
         
     | 
| 
      
 300 
     | 
    
         
            +
                }
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 303 
     | 
    
         
            +
            }
         
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 306 
     | 
    
         
            +
            method_name(ID mid, int depth)
         
     | 
| 
      
 307 
     | 
    
         
            +
            {
         
     | 
| 
      
 308 
     | 
    
         
            +
                VALUE result;
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                if (mid == ID_ALLOCATOR) 
         
     | 
| 
      
 311 
     | 
    
         
            +
                    result = rb_str_new2("allocate");
         
     | 
| 
      
 312 
     | 
    
         
            +
                else if (mid == 0)
         
     | 
| 
      
 313 
     | 
    
         
            +
                    result = rb_str_new2("[No method]");
         
     | 
| 
      
 314 
     | 
    
         
            +
                else
         
     | 
| 
      
 315 
     | 
    
         
            +
                    result = rb_String(ID2SYM(mid));
         
     | 
| 
      
 316 
     | 
    
         
            +
                
         
     | 
| 
      
 317 
     | 
    
         
            +
                if (depth > 0)
         
     | 
| 
      
 318 
     | 
    
         
            +
                {
         
     | 
| 
      
 319 
     | 
    
         
            +
                  char buffer[65];
         
     | 
| 
      
 320 
     | 
    
         
            +
                  sprintf(buffer, "(d%i)", depth);
         
     | 
| 
      
 321 
     | 
    
         
            +
                  rb_str_cat2(result, buffer);
         
     | 
| 
      
 322 
     | 
    
         
            +
                }
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 325 
     | 
    
         
            +
            }
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 328 
     | 
    
         
            +
            full_name(VALUE klass, ID mid, int depth)
         
     | 
| 
      
 329 
     | 
    
         
            +
            {
         
     | 
| 
      
 330 
     | 
    
         
            +
              VALUE result = klass_name(klass);
         
     | 
| 
      
 331 
     | 
    
         
            +
              rb_str_cat2(result, "#");
         
     | 
| 
      
 332 
     | 
    
         
            +
              rb_str_append(result, method_name(mid, depth));
         
     | 
| 
      
 333 
     | 
    
         
            +
              
         
     | 
| 
      
 334 
     | 
    
         
            +
              return result;
         
     | 
| 
      
 335 
     | 
    
         
            +
            }
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
            /* ================  Stack Handling   =================*/
         
     | 
| 
      
 338 
     | 
    
         
            +
            /* Creates a stack of prof_frame_t to keep track
         
     | 
| 
      
 339 
     | 
    
         
            +
               of timings for active methods. */
         
     | 
| 
      
 340 
     | 
    
         
            +
            static prof_stack_t *
         
     | 
| 
      
 341 
     | 
    
         
            +
            stack_create()
         
     | 
| 
      
 342 
     | 
    
         
            +
            {
         
     | 
| 
      
 343 
     | 
    
         
            +
                prof_stack_t *stack = ALLOC(prof_stack_t);
         
     | 
| 
      
 344 
     | 
    
         
            +
                stack->start = ALLOC_N(prof_frame_t, INITIAL_STACK_SIZE);
         
     | 
| 
      
 345 
     | 
    
         
            +
                stack->ptr = stack->start;
         
     | 
| 
      
 346 
     | 
    
         
            +
                stack->end = stack->start + INITIAL_STACK_SIZE;
         
     | 
| 
      
 347 
     | 
    
         
            +
                return stack;
         
     | 
| 
      
 348 
     | 
    
         
            +
            }
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
            static void
         
     | 
| 
      
 351 
     | 
    
         
            +
            stack_free(prof_stack_t *stack)
         
     | 
| 
      
 352 
     | 
    
         
            +
            {
         
     | 
| 
      
 353 
     | 
    
         
            +
                xfree(stack->start);
         
     | 
| 
      
 354 
     | 
    
         
            +
                xfree(stack);
         
     | 
| 
      
 355 
     | 
    
         
            +
            }
         
     | 
| 
      
 356 
     | 
    
         
            +
             
     | 
| 
      
 357 
     | 
    
         
            +
            static prof_frame_t *
         
     | 
| 
      
 358 
     | 
    
         
            +
            stack_push(prof_stack_t *stack)
         
     | 
| 
      
 359 
     | 
    
         
            +
            {
         
     | 
| 
      
 360 
     | 
    
         
            +
              /* Is there space on the stack?  If not, double
         
     | 
| 
      
 361 
     | 
    
         
            +
                 its size. */
         
     | 
| 
      
 362 
     | 
    
         
            +
              if (stack->ptr == stack->end)
         
     | 
| 
      
 363 
     | 
    
         
            +
              {
         
     | 
| 
      
 364 
     | 
    
         
            +
                size_t len = stack->ptr - stack->start;
         
     | 
| 
      
 365 
     | 
    
         
            +
                size_t new_capacity = (stack->end - stack->start) * 2;
         
     | 
| 
      
 366 
     | 
    
         
            +
                REALLOC_N(stack->start, prof_frame_t, new_capacity);
         
     | 
| 
      
 367 
     | 
    
         
            +
                stack->ptr = stack->start + len;
         
     | 
| 
      
 368 
     | 
    
         
            +
                stack->end = stack->start + new_capacity;
         
     | 
| 
      
 369 
     | 
    
         
            +
              }
         
     | 
| 
      
 370 
     | 
    
         
            +
              return stack->ptr++;
         
     | 
| 
      
 371 
     | 
    
         
            +
            }
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
            static prof_frame_t *
         
     | 
| 
      
 374 
     | 
    
         
            +
            stack_pop(prof_stack_t *stack)
         
     | 
| 
      
 375 
     | 
    
         
            +
            {
         
     | 
| 
      
 376 
     | 
    
         
            +
                if (stack->ptr == stack->start)
         
     | 
| 
      
 377 
     | 
    
         
            +
                  return NULL;
         
     | 
| 
      
 378 
     | 
    
         
            +
                else
         
     | 
| 
      
 379 
     | 
    
         
            +
                  return --stack->ptr;
         
     | 
| 
      
 380 
     | 
    
         
            +
            }
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
            static prof_frame_t *
         
     | 
| 
      
 383 
     | 
    
         
            +
            stack_peek(prof_stack_t *stack)
         
     | 
| 
      
 384 
     | 
    
         
            +
            {
         
     | 
| 
      
 385 
     | 
    
         
            +
                if (stack->ptr == stack->start)
         
     | 
| 
      
 386 
     | 
    
         
            +
                  return NULL;
         
     | 
| 
      
 387 
     | 
    
         
            +
                else
         
     | 
| 
      
 388 
     | 
    
         
            +
                  return stack->ptr - 1;
         
     | 
| 
      
 389 
     | 
    
         
            +
            }
         
     | 
| 
      
 390 
     | 
    
         
            +
             
     | 
| 
      
 391 
     | 
    
         
            +
            /* ================  Method Key   =================*/
         
     | 
| 
      
 392 
     | 
    
         
            +
            static int 
         
     | 
| 
      
 393 
     | 
    
         
            +
            method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2) 
         
     | 
| 
      
 394 
     | 
    
         
            +
            {
         
     | 
| 
      
 395 
     | 
    
         
            +
                return (key1->klass != key2->klass) || 
         
     | 
| 
      
 396 
     | 
    
         
            +
                       (key1->mid != key2->mid) || 
         
     | 
| 
      
 397 
     | 
    
         
            +
                       (key1->depth != key2->depth);
         
     | 
| 
      
 398 
     | 
    
         
            +
            }
         
     | 
| 
      
 399 
     | 
    
         
            +
             
     | 
| 
      
 400 
     | 
    
         
            +
            static int 
         
     | 
| 
      
 401 
     | 
    
         
            +
            method_table_hash(prof_method_key_t *key) 
         
     | 
| 
      
 402 
     | 
    
         
            +
            {
         
     | 
| 
      
 403 
     | 
    
         
            +
               return key->key;
         
     | 
| 
      
 404 
     | 
    
         
            +
            }
         
     | 
| 
      
 405 
     | 
    
         
            +
             
     | 
| 
      
 406 
     | 
    
         
            +
            static struct st_hash_type type_method_hash = {
         
     | 
| 
      
 407 
     | 
    
         
            +
                method_table_cmp,
         
     | 
| 
      
 408 
     | 
    
         
            +
                method_table_hash
         
     | 
| 
      
 409 
     | 
    
         
            +
            };
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
      
 411 
     | 
    
         
            +
            static void
         
     | 
| 
      
 412 
     | 
    
         
            +
            method_key(prof_method_key_t* key, VALUE klass, ID mid, int depth)
         
     | 
| 
      
 413 
     | 
    
         
            +
            {
         
     | 
| 
      
 414 
     | 
    
         
            +
                key->klass = klass;
         
     | 
| 
      
 415 
     | 
    
         
            +
                key->mid = mid;
         
     | 
| 
      
 416 
     | 
    
         
            +
                key->depth = depth;
         
     | 
| 
      
 417 
     | 
    
         
            +
                key->key = (klass << 4) + (mid << 2) + depth;
         
     | 
| 
      
 418 
     | 
    
         
            +
            }
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
            /* ================  Call Info   =================*/
         
     | 
| 
      
 422 
     | 
    
         
            +
            static st_table *
         
     | 
| 
      
 423 
     | 
    
         
            +
            call_info_table_create()
         
     | 
| 
      
 424 
     | 
    
         
            +
            {
         
     | 
| 
      
 425 
     | 
    
         
            +
              return st_init_table(&type_method_hash);
         
     | 
| 
      
 426 
     | 
    
         
            +
            }
         
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
      
 428 
     | 
    
         
            +
            static size_t
         
     | 
| 
      
 429 
     | 
    
         
            +
            call_info_table_insert(st_table *table, const prof_method_key_t *key, prof_call_info_t *val)
         
     | 
| 
      
 430 
     | 
    
         
            +
            {
         
     | 
| 
      
 431 
     | 
    
         
            +
              return st_insert(table, (st_data_t) key, (st_data_t) val);
         
     | 
| 
      
 432 
     | 
    
         
            +
            }
         
     | 
| 
      
 433 
     | 
    
         
            +
             
     | 
| 
      
 434 
     | 
    
         
            +
            static prof_call_info_t *
         
     | 
| 
      
 435 
     | 
    
         
            +
            call_info_table_lookup(st_table *table, const prof_method_key_t *key)
         
     | 
| 
      
 436 
     | 
    
         
            +
            {
         
     | 
| 
      
 437 
     | 
    
         
            +
                st_data_t val;
         
     | 
| 
      
 438 
     | 
    
         
            +
                if (st_lookup(table, (st_data_t) key, &val))
         
     | 
| 
      
 439 
     | 
    
         
            +
                {
         
     | 
| 
      
 440 
     | 
    
         
            +
                  return (prof_call_info_t *) val;
         
     | 
| 
      
 441 
     | 
    
         
            +
                }
         
     | 
| 
      
 442 
     | 
    
         
            +
                else
         
     | 
| 
      
 443 
     | 
    
         
            +
                {
         
     | 
| 
      
 444 
     | 
    
         
            +
                  return NULL;
         
     | 
| 
      
 445 
     | 
    
         
            +
                }
         
     | 
| 
      
 446 
     | 
    
         
            +
            }
         
     | 
| 
      
 447 
     | 
    
         
            +
             
     | 
| 
      
 448 
     | 
    
         
            +
            static void
         
     | 
| 
      
 449 
     | 
    
         
            +
            call_info_table_free(st_table *table)
         
     | 
| 
      
 450 
     | 
    
         
            +
            {
         
     | 
| 
      
 451 
     | 
    
         
            +
                st_free_table(table);
         
     | 
| 
      
 452 
     | 
    
         
            +
            }
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
            /* Document-class: RubyProf::CallInfo
         
     | 
| 
      
 455 
     | 
    
         
            +
            RubyProf::CallInfo is a helper class used by RubyProf::MethodInfo
         
     | 
| 
      
 456 
     | 
    
         
            +
            to keep track of which child methods were called and how long
         
     | 
| 
      
 457 
     | 
    
         
            +
            they took to execute. */
         
     | 
| 
      
 458 
     | 
    
         
            +
             
     | 
| 
      
 459 
     | 
    
         
            +
            /* :nodoc: */
         
     | 
| 
      
 460 
     | 
    
         
            +
            static prof_call_info_t *
         
     | 
| 
      
 461 
     | 
    
         
            +
            prof_call_info_create(prof_method_t* method, prof_call_info_t* parent)
         
     | 
| 
      
 462 
     | 
    
         
            +
            {
         
     | 
| 
      
 463 
     | 
    
         
            +
                prof_call_info_t *result = ALLOC(prof_call_info_t);
         
     | 
| 
      
 464 
     | 
    
         
            +
                result->object = Qnil;
         
     | 
| 
      
 465 
     | 
    
         
            +
                result->target = method;
         
     | 
| 
      
 466 
     | 
    
         
            +
                result->parent = parent;
         
     | 
| 
      
 467 
     | 
    
         
            +
                result->call_infos = call_info_table_create();
         
     | 
| 
      
 468 
     | 
    
         
            +
                result->children = Qnil;
         
     | 
| 
      
 469 
     | 
    
         
            +
             
     | 
| 
      
 470 
     | 
    
         
            +
                result->called = 0;
         
     | 
| 
      
 471 
     | 
    
         
            +
                result->total_time = 0;
         
     | 
| 
      
 472 
     | 
    
         
            +
                result->self_time = 0;
         
     | 
| 
      
 473 
     | 
    
         
            +
                result->wait_time = 0;
         
     | 
| 
      
 474 
     | 
    
         
            +
                result->line = 0;
         
     | 
| 
      
 475 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 476 
     | 
    
         
            +
            }
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
      
 478 
     | 
    
         
            +
            static void prof_method_mark(prof_method_t *method);
         
     | 
| 
      
 479 
     | 
    
         
            +
             
     | 
| 
      
 480 
     | 
    
         
            +
            static void
         
     | 
| 
      
 481 
     | 
    
         
            +
            prof_call_info_mark(prof_call_info_t *call_info)
         
     | 
| 
      
 482 
     | 
    
         
            +
            {
         
     | 
| 
      
 483 
     | 
    
         
            +
              {
         
     | 
| 
      
 484 
     | 
    
         
            +
                VALUE target = call_info->target->object;
         
     | 
| 
      
 485 
     | 
    
         
            +
                if (NIL_P(target))
         
     | 
| 
      
 486 
     | 
    
         
            +
                  prof_method_mark(call_info->target);
         
     | 
| 
      
 487 
     | 
    
         
            +
                else
         
     | 
| 
      
 488 
     | 
    
         
            +
                  rb_gc_mark(target);
         
     | 
| 
      
 489 
     | 
    
         
            +
              }
         
     | 
| 
      
 490 
     | 
    
         
            +
              rb_gc_mark(call_info->children);
         
     | 
| 
      
 491 
     | 
    
         
            +
              if (call_info->parent) {
         
     | 
| 
      
 492 
     | 
    
         
            +
                VALUE parent = call_info->parent->object;
         
     | 
| 
      
 493 
     | 
    
         
            +
                if (NIL_P(parent)) {
         
     | 
| 
      
 494 
     | 
    
         
            +
                  prof_call_info_mark(call_info->parent);
         
     | 
| 
      
 495 
     | 
    
         
            +
                }
         
     | 
| 
      
 496 
     | 
    
         
            +
                else {
         
     | 
| 
      
 497 
     | 
    
         
            +
                  rb_gc_mark(parent);
         
     | 
| 
      
 498 
     | 
    
         
            +
                }
         
     | 
| 
      
 499 
     | 
    
         
            +
              }
         
     | 
| 
      
 500 
     | 
    
         
            +
            }
         
     | 
| 
      
 501 
     | 
    
         
            +
             
     | 
| 
      
 502 
     | 
    
         
            +
            static void
         
     | 
| 
      
 503 
     | 
    
         
            +
            prof_call_info_free(prof_call_info_t *call_info)
         
     | 
| 
      
 504 
     | 
    
         
            +
            {
         
     | 
| 
      
 505 
     | 
    
         
            +
              call_info_table_free(call_info->call_infos); 
         
     | 
| 
      
 506 
     | 
    
         
            +
              xfree(call_info);
         
     | 
| 
      
 507 
     | 
    
         
            +
            }
         
     | 
| 
      
 508 
     | 
    
         
            +
             
     | 
| 
      
 509 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 510 
     | 
    
         
            +
            prof_call_info_wrap(prof_call_info_t *call_info)
         
     | 
| 
      
 511 
     | 
    
         
            +
            {
         
     | 
| 
      
 512 
     | 
    
         
            +
              if (call_info->object == Qnil)
         
     | 
| 
      
 513 
     | 
    
         
            +
              {
         
     | 
| 
      
 514 
     | 
    
         
            +
                call_info->object = Data_Wrap_Struct(cCallInfo, prof_call_info_mark, prof_call_info_free, call_info);
         
     | 
| 
      
 515 
     | 
    
         
            +
              }
         
     | 
| 
      
 516 
     | 
    
         
            +
              return call_info->object;
         
     | 
| 
      
 517 
     | 
    
         
            +
            }
         
     | 
| 
      
 518 
     | 
    
         
            +
             
     | 
| 
      
 519 
     | 
    
         
            +
            static prof_call_info_t *
         
     | 
| 
      
 520 
     | 
    
         
            +
            prof_get_call_info_result(VALUE obj)
         
     | 
| 
      
 521 
     | 
    
         
            +
            {
         
     | 
| 
      
 522 
     | 
    
         
            +
                if (BUILTIN_TYPE(obj) != T_DATA)
         
     | 
| 
      
 523 
     | 
    
         
            +
                {
         
     | 
| 
      
 524 
     | 
    
         
            +
                    /* Should never happen */
         
     | 
| 
      
 525 
     | 
    
         
            +
                  rb_raise(rb_eTypeError, "Not a call info object");
         
     | 
| 
      
 526 
     | 
    
         
            +
                }
         
     | 
| 
      
 527 
     | 
    
         
            +
                return (prof_call_info_t *) DATA_PTR(obj);
         
     | 
| 
      
 528 
     | 
    
         
            +
            }
         
     | 
| 
      
 529 
     | 
    
         
            +
             
     | 
| 
      
 530 
     | 
    
         
            +
             
     | 
| 
      
 531 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 532 
     | 
    
         
            +
               called -> MethodInfo
         
     | 
| 
      
 533 
     | 
    
         
            +
             
     | 
| 
      
 534 
     | 
    
         
            +
            Returns the target method. */
         
     | 
| 
      
 535 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 536 
     | 
    
         
            +
            prof_call_info_target(VALUE self)
         
     | 
| 
      
 537 
     | 
    
         
            +
            {
         
     | 
| 
      
 538 
     | 
    
         
            +
                /* Target is a pointer to a method_info - so we have to be careful
         
     | 
| 
      
 539 
     | 
    
         
            +
                   about the GC.  We will wrap the method_info but provide no
         
     | 
| 
      
 540 
     | 
    
         
            +
                   free method so the underlying object is not freed twice! */
         
     | 
| 
      
 541 
     | 
    
         
            +
                
         
     | 
| 
      
 542 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 543 
     | 
    
         
            +
                return prof_method_wrap(result->target);
         
     | 
| 
      
 544 
     | 
    
         
            +
            }
         
     | 
| 
      
 545 
     | 
    
         
            +
             
     | 
| 
      
 546 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 547 
     | 
    
         
            +
               called -> int
         
     | 
| 
      
 548 
     | 
    
         
            +
             
     | 
| 
      
 549 
     | 
    
         
            +
            Returns the total amount of times this method was called. */
         
     | 
| 
      
 550 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 551 
     | 
    
         
            +
            prof_call_info_called(VALUE self)
         
     | 
| 
      
 552 
     | 
    
         
            +
            {
         
     | 
| 
      
 553 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 554 
     | 
    
         
            +
                return INT2NUM(result->called);
         
     | 
| 
      
 555 
     | 
    
         
            +
            }
         
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
      
 557 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 558 
     | 
    
         
            +
               line_no -> int
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
               returns the line number of the method */
         
     | 
| 
      
 561 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 562 
     | 
    
         
            +
            prof_call_info_line(VALUE self)
         
     | 
| 
      
 563 
     | 
    
         
            +
            {
         
     | 
| 
      
 564 
     | 
    
         
            +
              prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 565 
     | 
    
         
            +
              return rb_int_new(result->line);
         
     | 
| 
      
 566 
     | 
    
         
            +
            }
         
     | 
| 
      
 567 
     | 
    
         
            +
             
     | 
| 
      
 568 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 569 
     | 
    
         
            +
               total_time -> float
         
     | 
| 
      
 570 
     | 
    
         
            +
             
     | 
| 
      
 571 
     | 
    
         
            +
            Returns the total amount of time spent in this method and its children. */
         
     | 
| 
      
 572 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 573 
     | 
    
         
            +
            prof_call_info_total_time(VALUE self)
         
     | 
| 
      
 574 
     | 
    
         
            +
            {
         
     | 
| 
      
 575 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 576 
     | 
    
         
            +
                return rb_float_new(convert_measurement(result->total_time));
         
     | 
| 
      
 577 
     | 
    
         
            +
            }
         
     | 
| 
      
 578 
     | 
    
         
            +
             
     | 
| 
      
 579 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 580 
     | 
    
         
            +
               self_time -> float
         
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
            Returns the total amount of time spent in this method. */
         
     | 
| 
      
 583 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 584 
     | 
    
         
            +
            prof_call_info_self_time(VALUE self)
         
     | 
| 
      
 585 
     | 
    
         
            +
            {
         
     | 
| 
      
 586 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 587 
     | 
    
         
            +
             
     | 
| 
      
 588 
     | 
    
         
            +
                return rb_float_new(convert_measurement(result->self_time));
         
     | 
| 
      
 589 
     | 
    
         
            +
            }
         
     | 
| 
      
 590 
     | 
    
         
            +
             
     | 
| 
      
 591 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 592 
     | 
    
         
            +
               wait_time -> float
         
     | 
| 
      
 593 
     | 
    
         
            +
             
     | 
| 
      
 594 
     | 
    
         
            +
            Returns the total amount of time this method waited for other threads. */
         
     | 
| 
      
 595 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 596 
     | 
    
         
            +
            prof_call_info_wait_time(VALUE self)
         
     | 
| 
      
 597 
     | 
    
         
            +
            {
         
     | 
| 
      
 598 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 599 
     | 
    
         
            +
             
     | 
| 
      
 600 
     | 
    
         
            +
                return rb_float_new(convert_measurement(result->wait_time));
         
     | 
| 
      
 601 
     | 
    
         
            +
            }
         
     | 
| 
      
 602 
     | 
    
         
            +
             
     | 
| 
      
 603 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 604 
     | 
    
         
            +
               parent -> call_info
         
     | 
| 
      
 605 
     | 
    
         
            +
             
     | 
| 
      
 606 
     | 
    
         
            +
            Returns the call_infos parent call_info object (the method that called this method).*/
         
     | 
| 
      
 607 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 608 
     | 
    
         
            +
            prof_call_info_parent(VALUE self)
         
     | 
| 
      
 609 
     | 
    
         
            +
            {
         
     | 
| 
      
 610 
     | 
    
         
            +
                prof_call_info_t *result = prof_get_call_info_result(self);
         
     | 
| 
      
 611 
     | 
    
         
            +
                if (result->parent)
         
     | 
| 
      
 612 
     | 
    
         
            +
                  return prof_call_info_wrap(result->parent);
         
     | 
| 
      
 613 
     | 
    
         
            +
                else
         
     | 
| 
      
 614 
     | 
    
         
            +
                  return Qnil;
         
     | 
| 
      
 615 
     | 
    
         
            +
            }
         
     | 
| 
      
 616 
     | 
    
         
            +
             
     | 
| 
      
 617 
     | 
    
         
            +
            static int
         
     | 
| 
      
 618 
     | 
    
         
            +
            prof_call_info_collect_children(st_data_t key, st_data_t value, st_data_t result)
         
     | 
| 
      
 619 
     | 
    
         
            +
            {
         
     | 
| 
      
 620 
     | 
    
         
            +
                prof_call_info_t *call_info = (prof_call_info_t *) value;
         
     | 
| 
      
 621 
     | 
    
         
            +
                VALUE arr = (VALUE) result;
         
     | 
| 
      
 622 
     | 
    
         
            +
                rb_ary_push(arr, prof_call_info_wrap(call_info));
         
     | 
| 
      
 623 
     | 
    
         
            +
                return ST_CONTINUE;
         
     | 
| 
      
 624 
     | 
    
         
            +
            }
         
     | 
| 
      
 625 
     | 
    
         
            +
             
     | 
| 
      
 626 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 627 
     | 
    
         
            +
               children -> hash
         
     | 
| 
      
 628 
     | 
    
         
            +
             
     | 
| 
      
 629 
     | 
    
         
            +
            Returns an array of call info objects of methods that this method 
         
     | 
| 
      
 630 
     | 
    
         
            +
            called (ie, children).*/
         
     | 
| 
      
 631 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 632 
     | 
    
         
            +
            prof_call_info_children(VALUE self)
         
     | 
| 
      
 633 
     | 
    
         
            +
            {
         
     | 
| 
      
 634 
     | 
    
         
            +
                prof_call_info_t *call_info = prof_get_call_info_result(self);
         
     | 
| 
      
 635 
     | 
    
         
            +
                if (call_info->children == Qnil)
         
     | 
| 
      
 636 
     | 
    
         
            +
                {
         
     | 
| 
      
 637 
     | 
    
         
            +
                  call_info->children = rb_ary_new();
         
     | 
| 
      
 638 
     | 
    
         
            +
                  st_foreach(call_info->call_infos, prof_call_info_collect_children, call_info->children);
         
     | 
| 
      
 639 
     | 
    
         
            +
                }
         
     | 
| 
      
 640 
     | 
    
         
            +
                return call_info->children;
         
     | 
| 
      
 641 
     | 
    
         
            +
            }
         
     | 
| 
      
 642 
     | 
    
         
            +
             
     | 
| 
      
 643 
     | 
    
         
            +
            /* ================  Call Infos   =================*/
         
     | 
| 
      
 644 
     | 
    
         
            +
            static prof_call_infos_t*
         
     | 
| 
      
 645 
     | 
    
         
            +
            prof_call_infos_create()
         
     | 
| 
      
 646 
     | 
    
         
            +
            {
         
     | 
| 
      
 647 
     | 
    
         
            +
               prof_call_infos_t *result = ALLOC(prof_call_infos_t);
         
     | 
| 
      
 648 
     | 
    
         
            +
               result->start = ALLOC_N(prof_call_info_t*, INITIAL_CALL_INFOS_SIZE);
         
     | 
| 
      
 649 
     | 
    
         
            +
               result->end = result->start + INITIAL_CALL_INFOS_SIZE;
         
     | 
| 
      
 650 
     | 
    
         
            +
               result->ptr = result->start;
         
     | 
| 
      
 651 
     | 
    
         
            +
               result->object = Qnil;
         
     | 
| 
      
 652 
     | 
    
         
            +
               return result;
         
     | 
| 
      
 653 
     | 
    
         
            +
            }
         
     | 
| 
      
 654 
     | 
    
         
            +
             
     | 
| 
      
 655 
     | 
    
         
            +
            static void
         
     | 
| 
      
 656 
     | 
    
         
            +
            prof_call_infos_free(prof_call_infos_t *call_infos)
         
     | 
| 
      
 657 
     | 
    
         
            +
            {
         
     | 
| 
      
 658 
     | 
    
         
            +
              xfree(call_infos->start);
         
     | 
| 
      
 659 
     | 
    
         
            +
              xfree(call_infos);
         
     | 
| 
      
 660 
     | 
    
         
            +
            }
         
     | 
| 
      
 661 
     | 
    
         
            +
             
     | 
| 
      
 662 
     | 
    
         
            +
            static void
         
     | 
| 
      
 663 
     | 
    
         
            +
            prof_add_call_info(prof_call_infos_t *call_infos, prof_call_info_t *call_info)
         
     | 
| 
      
 664 
     | 
    
         
            +
            {
         
     | 
| 
      
 665 
     | 
    
         
            +
              if (call_infos->ptr == call_infos->end)
         
     | 
| 
      
 666 
     | 
    
         
            +
              {
         
     | 
| 
      
 667 
     | 
    
         
            +
                size_t len = call_infos->ptr - call_infos->start;
         
     | 
| 
      
 668 
     | 
    
         
            +
                size_t new_capacity = (call_infos->end - call_infos->start) * 2;
         
     | 
| 
      
 669 
     | 
    
         
            +
                REALLOC_N(call_infos->start, prof_call_info_t*, new_capacity);
         
     | 
| 
      
 670 
     | 
    
         
            +
                call_infos->ptr = call_infos->start + len;
         
     | 
| 
      
 671 
     | 
    
         
            +
                call_infos->end = call_infos->start + new_capacity;
         
     | 
| 
      
 672 
     | 
    
         
            +
              }
         
     | 
| 
      
 673 
     | 
    
         
            +
              *call_infos->ptr = call_info;
         
     | 
| 
      
 674 
     | 
    
         
            +
              call_infos->ptr++;
         
     | 
| 
      
 675 
     | 
    
         
            +
            }
         
     | 
| 
      
 676 
     | 
    
         
            +
             
     | 
| 
      
 677 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 678 
     | 
    
         
            +
            prof_call_infos_wrap(prof_call_infos_t *call_infos)
         
     | 
| 
      
 679 
     | 
    
         
            +
            {
         
     | 
| 
      
 680 
     | 
    
         
            +
              if (call_infos->object == Qnil)
         
     | 
| 
      
 681 
     | 
    
         
            +
              {
         
     | 
| 
      
 682 
     | 
    
         
            +
                prof_call_info_t **i;
         
     | 
| 
      
 683 
     | 
    
         
            +
                call_infos->object = rb_ary_new();
         
     | 
| 
      
 684 
     | 
    
         
            +
                for(i=call_infos->start; i<call_infos->ptr; i++)
         
     | 
| 
      
 685 
     | 
    
         
            +
                {
         
     | 
| 
      
 686 
     | 
    
         
            +
                  VALUE call_info = prof_call_info_wrap(*i);
         
     | 
| 
      
 687 
     | 
    
         
            +
                  rb_ary_push(call_infos->object, call_info);
         
     | 
| 
      
 688 
     | 
    
         
            +
                }
         
     | 
| 
      
 689 
     | 
    
         
            +
              }
         
     | 
| 
      
 690 
     | 
    
         
            +
              return call_infos->object;
         
     | 
| 
      
 691 
     | 
    
         
            +
            }
         
     | 
| 
      
 692 
     | 
    
         
            +
             
     | 
| 
      
 693 
     | 
    
         
            +
             
     | 
| 
      
 694 
     | 
    
         
            +
            /* ================  Method Info   =================*/
         
     | 
| 
      
 695 
     | 
    
         
            +
            /* Document-class: RubyProf::MethodInfo
         
     | 
| 
      
 696 
     | 
    
         
            +
            The RubyProf::MethodInfo class stores profiling data for a method.
         
     | 
| 
      
 697 
     | 
    
         
            +
            One instance of the RubyProf::MethodInfo class is created per method
         
     | 
| 
      
 698 
     | 
    
         
            +
            called per thread.  Thus, if a method is called in two different
         
     | 
| 
      
 699 
     | 
    
         
            +
            thread then there will be two RubyProf::MethodInfo objects
         
     | 
| 
      
 700 
     | 
    
         
            +
            created.  RubyProf::MethodInfo objects can be accessed via
         
     | 
| 
      
 701 
     | 
    
         
            +
            the RubyProf::Result object.
         
     | 
| 
      
 702 
     | 
    
         
            +
            */
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
            static prof_method_t*
         
     | 
| 
      
 705 
     | 
    
         
            +
            prof_method_create(prof_method_key_t *key, const char* source_file, int line)
         
     | 
| 
      
 706 
     | 
    
         
            +
            {
         
     | 
| 
      
 707 
     | 
    
         
            +
                prof_method_t *result = ALLOC(prof_method_t);
         
     | 
| 
      
 708 
     | 
    
         
            +
                result->object = Qnil;
         
     | 
| 
      
 709 
     | 
    
         
            +
                result->key = ALLOC(prof_method_key_t);
         
     | 
| 
      
 710 
     | 
    
         
            +
                method_key(result->key, key->klass, key->mid, key->depth);   
         
     | 
| 
      
 711 
     | 
    
         
            +
             
     | 
| 
      
 712 
     | 
    
         
            +
                result->call_infos = prof_call_infos_create();
         
     | 
| 
      
 713 
     | 
    
         
            +
             
     | 
| 
      
 714 
     | 
    
         
            +
                result->active = 0;
         
     | 
| 
      
 715 
     | 
    
         
            +
             
     | 
| 
      
 716 
     | 
    
         
            +
                if (source_file != NULL) 
         
     | 
| 
      
 717 
     | 
    
         
            +
                {
         
     | 
| 
      
 718 
     | 
    
         
            +
                  int len = strlen(source_file) + 1;    
         
     | 
| 
      
 719 
     | 
    
         
            +
                  char *buffer = ALLOC_N(char, len);
         
     | 
| 
      
 720 
     | 
    
         
            +
             
     | 
| 
      
 721 
     | 
    
         
            +
                  MEMCPY(buffer, source_file, char, len);
         
     | 
| 
      
 722 
     | 
    
         
            +
                  result->source_file = buffer;
         
     | 
| 
      
 723 
     | 
    
         
            +
                }
         
     | 
| 
      
 724 
     | 
    
         
            +
                else 
         
     | 
| 
      
 725 
     | 
    
         
            +
                {    
         
     | 
| 
      
 726 
     | 
    
         
            +
                  result->source_file = source_file;
         
     | 
| 
      
 727 
     | 
    
         
            +
                }      
         
     | 
| 
      
 728 
     | 
    
         
            +
                result->line = line;
         
     | 
| 
      
 729 
     | 
    
         
            +
             
     | 
| 
      
 730 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 731 
     | 
    
         
            +
            }
         
     | 
| 
      
 732 
     | 
    
         
            +
             
     | 
| 
      
 733 
     | 
    
         
            +
            static void
         
     | 
| 
      
 734 
     | 
    
         
            +
            prof_method_mark(prof_method_t *method)
         
     | 
| 
      
 735 
     | 
    
         
            +
            {
         
     | 
| 
      
 736 
     | 
    
         
            +
              rb_gc_mark(method->call_infos->object);
         
     | 
| 
      
 737 
     | 
    
         
            +
              rb_gc_mark(method->key->klass);
         
     | 
| 
      
 738 
     | 
    
         
            +
            }
         
     | 
| 
      
 739 
     | 
    
         
            +
             
     | 
| 
      
 740 
     | 
    
         
            +
            static void
         
     | 
| 
      
 741 
     | 
    
         
            +
            prof_method_free(prof_method_t *method)
         
     | 
| 
      
 742 
     | 
    
         
            +
            {
         
     | 
| 
      
 743 
     | 
    
         
            +
              if (method->source_file)
         
     | 
| 
      
 744 
     | 
    
         
            +
              {
         
     | 
| 
      
 745 
     | 
    
         
            +
                xfree((char*)method->source_file);    
         
     | 
| 
      
 746 
     | 
    
         
            +
              }
         
     | 
| 
      
 747 
     | 
    
         
            +
             
     | 
| 
      
 748 
     | 
    
         
            +
              prof_call_infos_free(method->call_infos);
         
     | 
| 
      
 749 
     | 
    
         
            +
              xfree(method->key);
         
     | 
| 
      
 750 
     | 
    
         
            +
              xfree(method);
         
     | 
| 
      
 751 
     | 
    
         
            +
            }
         
     | 
| 
      
 752 
     | 
    
         
            +
             
     | 
| 
      
 753 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 754 
     | 
    
         
            +
            prof_method_wrap(prof_method_t *result)
         
     | 
| 
      
 755 
     | 
    
         
            +
            {
         
     | 
| 
      
 756 
     | 
    
         
            +
              if (result->object == Qnil)
         
     | 
| 
      
 757 
     | 
    
         
            +
              {
         
     | 
| 
      
 758 
     | 
    
         
            +
                result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_free, result);
         
     | 
| 
      
 759 
     | 
    
         
            +
              }
         
     | 
| 
      
 760 
     | 
    
         
            +
              return result->object;
         
     | 
| 
      
 761 
     | 
    
         
            +
            }
         
     | 
| 
      
 762 
     | 
    
         
            +
             
     | 
| 
      
 763 
     | 
    
         
            +
            static prof_method_t *
         
     | 
| 
      
 764 
     | 
    
         
            +
            get_prof_method(VALUE obj)
         
     | 
| 
      
 765 
     | 
    
         
            +
            {
         
     | 
| 
      
 766 
     | 
    
         
            +
                return (prof_method_t *) DATA_PTR(obj);
         
     | 
| 
      
 767 
     | 
    
         
            +
            }
         
     | 
| 
      
 768 
     | 
    
         
            +
             
     | 
| 
      
 769 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 770 
     | 
    
         
            +
               line_no -> int
         
     | 
| 
      
 771 
     | 
    
         
            +
             
     | 
| 
      
 772 
     | 
    
         
            +
               returns the line number of the method */
         
     | 
| 
      
 773 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 774 
     | 
    
         
            +
            prof_method_line(VALUE self)
         
     | 
| 
      
 775 
     | 
    
         
            +
            {
         
     | 
| 
      
 776 
     | 
    
         
            +
                return rb_int_new(get_prof_method(self)->line);
         
     | 
| 
      
 777 
     | 
    
         
            +
            }
         
     | 
| 
      
 778 
     | 
    
         
            +
             
     | 
| 
      
 779 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 780 
     | 
    
         
            +
               source_file => string
         
     | 
| 
      
 781 
     | 
    
         
            +
             
     | 
| 
      
 782 
     | 
    
         
            +
            return the source file of the method 
         
     | 
| 
      
 783 
     | 
    
         
            +
            */
         
     | 
| 
      
 784 
     | 
    
         
            +
            static VALUE prof_method_source_file(VALUE self)
         
     | 
| 
      
 785 
     | 
    
         
            +
            {
         
     | 
| 
      
 786 
     | 
    
         
            +
                const char* sf = get_prof_method(self)->source_file;
         
     | 
| 
      
 787 
     | 
    
         
            +
                if(!sf)
         
     | 
| 
      
 788 
     | 
    
         
            +
                {
         
     | 
| 
      
 789 
     | 
    
         
            +
                  return rb_str_new2("ruby_runtime");
         
     | 
| 
      
 790 
     | 
    
         
            +
                }
         
     | 
| 
      
 791 
     | 
    
         
            +
                else
         
     | 
| 
      
 792 
     | 
    
         
            +
                {
         
     | 
| 
      
 793 
     | 
    
         
            +
                  return rb_str_new2(sf);
         
     | 
| 
      
 794 
     | 
    
         
            +
                }
         
     | 
| 
      
 795 
     | 
    
         
            +
            }
         
     | 
| 
      
 796 
     | 
    
         
            +
             
     | 
| 
      
 797 
     | 
    
         
            +
             
     | 
| 
      
 798 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 799 
     | 
    
         
            +
               method_class -> klass
         
     | 
| 
      
 800 
     | 
    
         
            +
             
     | 
| 
      
 801 
     | 
    
         
            +
            Returns the Ruby klass that owns this method. */
         
     | 
| 
      
 802 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 803 
     | 
    
         
            +
            prof_method_klass(VALUE self)
         
     | 
| 
      
 804 
     | 
    
         
            +
            {
         
     | 
| 
      
 805 
     | 
    
         
            +
                prof_method_t *result = get_prof_method(self);
         
     | 
| 
      
 806 
     | 
    
         
            +
                return result->key->klass;
         
     | 
| 
      
 807 
     | 
    
         
            +
            }
         
     | 
| 
      
 808 
     | 
    
         
            +
             
     | 
| 
      
 809 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 810 
     | 
    
         
            +
               method_id -> ID
         
     | 
| 
      
 811 
     | 
    
         
            +
             
     | 
| 
      
 812 
     | 
    
         
            +
            Returns the id of this method. */
         
     | 
| 
      
 813 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 814 
     | 
    
         
            +
            prof_method_id(VALUE self)
         
     | 
| 
      
 815 
     | 
    
         
            +
            {
         
     | 
| 
      
 816 
     | 
    
         
            +
                prof_method_t *result = get_prof_method(self);
         
     | 
| 
      
 817 
     | 
    
         
            +
                return ID2SYM(result->key->mid);
         
     | 
| 
      
 818 
     | 
    
         
            +
            }
         
     | 
| 
      
 819 
     | 
    
         
            +
             
     | 
| 
      
 820 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 821 
     | 
    
         
            +
               klass_name -> string
         
     | 
| 
      
 822 
     | 
    
         
            +
             
     | 
| 
      
 823 
     | 
    
         
            +
            Returns the name of this method's class.  Singleton classes
         
     | 
| 
      
 824 
     | 
    
         
            +
            will have the form <Object::Object>. */
         
     | 
| 
      
 825 
     | 
    
         
            +
             
     | 
| 
      
 826 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 827 
     | 
    
         
            +
            prof_klass_name(VALUE self)
         
     | 
| 
      
 828 
     | 
    
         
            +
            {
         
     | 
| 
      
 829 
     | 
    
         
            +
                prof_method_t *method = get_prof_method(self);
         
     | 
| 
      
 830 
     | 
    
         
            +
                return klass_name(method->key->klass);
         
     | 
| 
      
 831 
     | 
    
         
            +
            }
         
     | 
| 
      
 832 
     | 
    
         
            +
             
     | 
| 
      
 833 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 834 
     | 
    
         
            +
               method_name -> string
         
     | 
| 
      
 835 
     | 
    
         
            +
             
     | 
| 
      
 836 
     | 
    
         
            +
            Returns the name of this method in the format Object#method.  Singletons
         
     | 
| 
      
 837 
     | 
    
         
            +
            methods will be returned in the format <Object::Object>#method.*/
         
     | 
| 
      
 838 
     | 
    
         
            +
             
     | 
| 
      
 839 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 840 
     | 
    
         
            +
            prof_method_name(VALUE self, int depth)
         
     | 
| 
      
 841 
     | 
    
         
            +
            {
         
     | 
| 
      
 842 
     | 
    
         
            +
                prof_method_t *method = get_prof_method(self);
         
     | 
| 
      
 843 
     | 
    
         
            +
                return method_name(method->key->mid, depth);
         
     | 
| 
      
 844 
     | 
    
         
            +
            }
         
     | 
| 
      
 845 
     | 
    
         
            +
             
     | 
| 
      
 846 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 847 
     | 
    
         
            +
               full_name -> string
         
     | 
| 
      
 848 
     | 
    
         
            +
             
     | 
| 
      
 849 
     | 
    
         
            +
            Returns the full name of this method in the format Object#method.*/
         
     | 
| 
      
 850 
     | 
    
         
            +
             
     | 
| 
      
 851 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 852 
     | 
    
         
            +
            prof_full_name(VALUE self)
         
     | 
| 
      
 853 
     | 
    
         
            +
            {
         
     | 
| 
      
 854 
     | 
    
         
            +
                prof_method_t *method = get_prof_method(self);
         
     | 
| 
      
 855 
     | 
    
         
            +
                return full_name(method->key->klass, method->key->mid, method->key->depth);
         
     | 
| 
      
 856 
     | 
    
         
            +
            }
         
     | 
| 
      
 857 
     | 
    
         
            +
             
     | 
| 
      
 858 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 859 
     | 
    
         
            +
               call_infos -> Array of call_info
         
     | 
| 
      
 860 
     | 
    
         
            +
             
     | 
| 
      
 861 
     | 
    
         
            +
            Returns an array of call info objects that contain profiling information 
         
     | 
| 
      
 862 
     | 
    
         
            +
            about the current method.*/
         
     | 
| 
      
 863 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 864 
     | 
    
         
            +
            prof_method_call_infos(VALUE self)
         
     | 
| 
      
 865 
     | 
    
         
            +
            {
         
     | 
| 
      
 866 
     | 
    
         
            +
                prof_method_t *method = get_prof_method(self);
         
     | 
| 
      
 867 
     | 
    
         
            +
                return prof_call_infos_wrap(method->call_infos);
         
     | 
| 
      
 868 
     | 
    
         
            +
            }
         
     | 
| 
      
 869 
     | 
    
         
            +
             
     | 
| 
      
 870 
     | 
    
         
            +
            static int
         
     | 
| 
      
 871 
     | 
    
         
            +
            collect_methods(st_data_t key, st_data_t value, st_data_t result)
         
     | 
| 
      
 872 
     | 
    
         
            +
            {
         
     | 
| 
      
 873 
     | 
    
         
            +
                /* Called for each method stored in a thread's method table. 
         
     | 
| 
      
 874 
     | 
    
         
            +
                   We want to store the method info information into an array.*/
         
     | 
| 
      
 875 
     | 
    
         
            +
                VALUE methods = (VALUE) result;
         
     | 
| 
      
 876 
     | 
    
         
            +
                prof_method_t *method = (prof_method_t *) value;
         
     | 
| 
      
 877 
     | 
    
         
            +
                rb_ary_push(methods, prof_method_wrap(method));
         
     | 
| 
      
 878 
     | 
    
         
            +
             
     | 
| 
      
 879 
     | 
    
         
            +
                /* Wrap call info objects */
         
     | 
| 
      
 880 
     | 
    
         
            +
                prof_call_infos_wrap(method->call_infos);
         
     | 
| 
      
 881 
     | 
    
         
            +
             
     | 
| 
      
 882 
     | 
    
         
            +
                return ST_CONTINUE;
         
     | 
| 
      
 883 
     | 
    
         
            +
            }
         
     | 
| 
      
 884 
     | 
    
         
            +
             
     | 
| 
      
 885 
     | 
    
         
            +
            /* ================  Method Table   =================*/
         
     | 
| 
      
 886 
     | 
    
         
            +
            static st_table *
         
     | 
| 
      
 887 
     | 
    
         
            +
            method_table_create()
         
     | 
| 
      
 888 
     | 
    
         
            +
            {
         
     | 
| 
      
 889 
     | 
    
         
            +
              return st_init_table(&type_method_hash);
         
     | 
| 
      
 890 
     | 
    
         
            +
            }
         
     | 
| 
      
 891 
     | 
    
         
            +
             
     | 
| 
      
 892 
     | 
    
         
            +
            static size_t
         
     | 
| 
      
 893 
     | 
    
         
            +
            method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
         
     | 
| 
      
 894 
     | 
    
         
            +
            {
         
     | 
| 
      
 895 
     | 
    
         
            +
              return st_insert(table, (st_data_t) key, (st_data_t) val);
         
     | 
| 
      
 896 
     | 
    
         
            +
            }
         
     | 
| 
      
 897 
     | 
    
         
            +
             
     | 
| 
      
 898 
     | 
    
         
            +
            static prof_method_t *
         
     | 
| 
      
 899 
     | 
    
         
            +
            method_table_lookup(st_table *table, const prof_method_key_t* key)
         
     | 
| 
      
 900 
     | 
    
         
            +
            {
         
     | 
| 
      
 901 
     | 
    
         
            +
                st_data_t val;
         
     | 
| 
      
 902 
     | 
    
         
            +
                if (st_lookup(table, (st_data_t)key, &val))
         
     | 
| 
      
 903 
     | 
    
         
            +
                {
         
     | 
| 
      
 904 
     | 
    
         
            +
                  return (prof_method_t *) val;
         
     | 
| 
      
 905 
     | 
    
         
            +
                }
         
     | 
| 
      
 906 
     | 
    
         
            +
                else 
         
     | 
| 
      
 907 
     | 
    
         
            +
                {
         
     | 
| 
      
 908 
     | 
    
         
            +
                  return NULL;
         
     | 
| 
      
 909 
     | 
    
         
            +
                }
         
     | 
| 
      
 910 
     | 
    
         
            +
            }
         
     | 
| 
      
 911 
     | 
    
         
            +
             
     | 
| 
      
 912 
     | 
    
         
            +
             
     | 
| 
      
 913 
     | 
    
         
            +
            static void
         
     | 
| 
      
 914 
     | 
    
         
            +
            method_table_free(st_table *table)
         
     | 
| 
      
 915 
     | 
    
         
            +
            {
         
     | 
| 
      
 916 
     | 
    
         
            +
                /* Don't free the contents since they are wrapped by
         
     | 
| 
      
 917 
     | 
    
         
            +
                   Ruby objects! */
         
     | 
| 
      
 918 
     | 
    
         
            +
                st_free_table(table);
         
     | 
| 
      
 919 
     | 
    
         
            +
            }
         
     | 
| 
      
 920 
     | 
    
         
            +
             
     | 
| 
      
 921 
     | 
    
         
            +
             
     | 
| 
      
 922 
     | 
    
         
            +
            /* ================  Thread Handling   =================*/
         
     | 
| 
      
 923 
     | 
    
         
            +
             
     | 
| 
      
 924 
     | 
    
         
            +
            /* ---- Keeps track of thread's stack and methods ---- */
         
     | 
| 
      
 925 
     | 
    
         
            +
            static thread_data_t*
         
     | 
| 
      
 926 
     | 
    
         
            +
            thread_data_create()
         
     | 
| 
      
 927 
     | 
    
         
            +
            {
         
     | 
| 
      
 928 
     | 
    
         
            +
                thread_data_t* result = ALLOC(thread_data_t);
         
     | 
| 
      
 929 
     | 
    
         
            +
                result->stack = stack_create();
         
     | 
| 
      
 930 
     | 
    
         
            +
                result->method_table = method_table_create();
         
     | 
| 
      
 931 
     | 
    
         
            +
                result->last_switch = get_measurement();
         
     | 
| 
      
 932 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 933 
     | 
    
         
            +
            }
         
     | 
| 
      
 934 
     | 
    
         
            +
             
     | 
| 
      
 935 
     | 
    
         
            +
            static void
         
     | 
| 
      
 936 
     | 
    
         
            +
            thread_data_free(thread_data_t* thread_data)
         
     | 
| 
      
 937 
     | 
    
         
            +
            {
         
     | 
| 
      
 938 
     | 
    
         
            +
                method_table_free(thread_data->method_table);
         
     | 
| 
      
 939 
     | 
    
         
            +
                stack_free(thread_data->stack);
         
     | 
| 
      
 940 
     | 
    
         
            +
                xfree(thread_data);
         
     | 
| 
      
 941 
     | 
    
         
            +
            }
         
     | 
| 
      
 942 
     | 
    
         
            +
             
     | 
| 
      
 943 
     | 
    
         
            +
            /* ---- Hash, keyed on thread, that stores thread's stack
         
     | 
| 
      
 944 
     | 
    
         
            +
                    and methods---- */
         
     | 
| 
      
 945 
     | 
    
         
            +
             
     | 
| 
      
 946 
     | 
    
         
            +
            static st_table *
         
     | 
| 
      
 947 
     | 
    
         
            +
            threads_table_create()
         
     | 
| 
      
 948 
     | 
    
         
            +
            {
         
     | 
| 
      
 949 
     | 
    
         
            +
                return st_init_numtable();
         
     | 
| 
      
 950 
     | 
    
         
            +
            }
         
     | 
| 
      
 951 
     | 
    
         
            +
             
     | 
| 
      
 952 
     | 
    
         
            +
            static size_t
         
     | 
| 
      
 953 
     | 
    
         
            +
            threads_table_insert(st_table *table, VALUE thread, thread_data_t *thread_data)
         
     | 
| 
      
 954 
     | 
    
         
            +
            {
         
     | 
| 
      
 955 
     | 
    
         
            +
                /* Its too slow to key on the real thread id so just typecast thread instead. */
         
     | 
| 
      
 956 
     | 
    
         
            +
                return st_insert(table, (st_data_t) thread, (st_data_t) thread_data);
         
     | 
| 
      
 957 
     | 
    
         
            +
            }
         
     | 
| 
      
 958 
     | 
    
         
            +
             
     | 
| 
      
 959 
     | 
    
         
            +
            static thread_data_t *
         
     | 
| 
      
 960 
     | 
    
         
            +
            threads_table_lookup(st_table *table, VALUE thread_id)
         
     | 
| 
      
 961 
     | 
    
         
            +
            {
         
     | 
| 
      
 962 
     | 
    
         
            +
                thread_data_t* result;
         
     | 
| 
      
 963 
     | 
    
         
            +
                st_data_t val;
         
     | 
| 
      
 964 
     | 
    
         
            +
             
     | 
| 
      
 965 
     | 
    
         
            +
                /* Its too slow to key on the real thread id so just typecast thread instead. */
         
     | 
| 
      
 966 
     | 
    
         
            +
                if (st_lookup(table, (st_data_t) thread_id, &val))
         
     | 
| 
      
 967 
     | 
    
         
            +
                {
         
     | 
| 
      
 968 
     | 
    
         
            +
                  result = (thread_data_t *) val;
         
     | 
| 
      
 969 
     | 
    
         
            +
                }
         
     | 
| 
      
 970 
     | 
    
         
            +
                else
         
     | 
| 
      
 971 
     | 
    
         
            +
                {
         
     | 
| 
      
 972 
     | 
    
         
            +
                    result = thread_data_create();
         
     | 
| 
      
 973 
     | 
    
         
            +
                    result->thread_id = thread_id;
         
     | 
| 
      
 974 
     | 
    
         
            +
             
     | 
| 
      
 975 
     | 
    
         
            +
                    /* Insert the table */
         
     | 
| 
      
 976 
     | 
    
         
            +
                    threads_table_insert(threads_tbl, thread_id, result);
         
     | 
| 
      
 977 
     | 
    
         
            +
                }
         
     | 
| 
      
 978 
     | 
    
         
            +
                return result;
         
     | 
| 
      
 979 
     | 
    
         
            +
            }
         
     | 
| 
      
 980 
     | 
    
         
            +
             
     | 
| 
      
 981 
     | 
    
         
            +
            static int
         
     | 
| 
      
 982 
     | 
    
         
            +
            free_thread_data(st_data_t key, st_data_t value, st_data_t dummy)
         
     | 
| 
      
 983 
     | 
    
         
            +
            {
         
     | 
| 
      
 984 
     | 
    
         
            +
                thread_data_free((thread_data_t*)value);
         
     | 
| 
      
 985 
     | 
    
         
            +
                return ST_CONTINUE;
         
     | 
| 
      
 986 
     | 
    
         
            +
            }
         
     | 
| 
      
 987 
     | 
    
         
            +
             
     | 
| 
      
 988 
     | 
    
         
            +
             
     | 
| 
      
 989 
     | 
    
         
            +
            static void
         
     | 
| 
      
 990 
     | 
    
         
            +
            threads_table_free(st_table *table)
         
     | 
| 
      
 991 
     | 
    
         
            +
            {
         
     | 
| 
      
 992 
     | 
    
         
            +
                st_foreach(table, free_thread_data, 0);
         
     | 
| 
      
 993 
     | 
    
         
            +
                st_free_table(table);
         
     | 
| 
      
 994 
     | 
    
         
            +
            }
         
     | 
| 
      
 995 
     | 
    
         
            +
             
     | 
| 
      
 996 
     | 
    
         
            +
             
     | 
| 
      
 997 
     | 
    
         
            +
            static int
         
     | 
| 
      
 998 
     | 
    
         
            +
            collect_threads(st_data_t key, st_data_t value, st_data_t result)
         
     | 
| 
      
 999 
     | 
    
         
            +
            {
         
     | 
| 
      
 1000 
     | 
    
         
            +
                /* Although threads are keyed on an id, that is actually a 
         
     | 
| 
      
 1001 
     | 
    
         
            +
                   pointer to the VALUE object of the thread.  So its bogus.
         
     | 
| 
      
 1002 
     | 
    
         
            +
                   However, in thread_data is the real thread id stored
         
     | 
| 
      
 1003 
     | 
    
         
            +
                   as an int. */
         
     | 
| 
      
 1004 
     | 
    
         
            +
                thread_data_t* thread_data = (thread_data_t*) value;
         
     | 
| 
      
 1005 
     | 
    
         
            +
                VALUE threads_hash = (VALUE) result;
         
     | 
| 
      
 1006 
     | 
    
         
            +
             
     | 
| 
      
 1007 
     | 
    
         
            +
                VALUE methods = rb_ary_new();
         
     | 
| 
      
 1008 
     | 
    
         
            +
             
     | 
| 
      
 1009 
     | 
    
         
            +
                /* Now collect an array of all the called methods */
         
     | 
| 
      
 1010 
     | 
    
         
            +
                st_table* method_table = thread_data->method_table;
         
     | 
| 
      
 1011 
     | 
    
         
            +
                st_foreach(method_table, collect_methods, methods);
         
     | 
| 
      
 1012 
     | 
    
         
            +
             
         
     | 
| 
      
 1013 
     | 
    
         
            +
                /* Store the results in the threads hash keyed on the thread id. */
         
     | 
| 
      
 1014 
     | 
    
         
            +
                rb_hash_aset(threads_hash, thread_data->thread_id, methods);
         
     | 
| 
      
 1015 
     | 
    
         
            +
             
     | 
| 
      
 1016 
     | 
    
         
            +
                return ST_CONTINUE;
         
     | 
| 
      
 1017 
     | 
    
         
            +
            }
         
     | 
| 
      
 1018 
     | 
    
         
            +
             
     | 
| 
      
 1019 
     | 
    
         
            +
             
     | 
| 
      
 1020 
     | 
    
         
            +
            /* ================  Profiling    =================*/
         
     | 
| 
      
 1021 
     | 
    
         
            +
            /* Copied from eval.c */
         
     | 
| 
      
 1022 
     | 
    
         
            +
            #ifdef DEBUG
         
     | 
| 
      
 1023 
     | 
    
         
            +
            static char *
         
     | 
| 
      
 1024 
     | 
    
         
            +
            get_event_name(rb_event_flag_t event)
         
     | 
| 
      
 1025 
     | 
    
         
            +
            {
         
     | 
| 
      
 1026 
     | 
    
         
            +
              switch (event) {
         
     | 
| 
      
 1027 
     | 
    
         
            +
                case RUBY_EVENT_LINE:
         
     | 
| 
      
 1028 
     | 
    
         
            +
              return "line";
         
     | 
| 
      
 1029 
     | 
    
         
            +
                case RUBY_EVENT_CLASS:
         
     | 
| 
      
 1030 
     | 
    
         
            +
              return "class";
         
     | 
| 
      
 1031 
     | 
    
         
            +
                case RUBY_EVENT_END:
         
     | 
| 
      
 1032 
     | 
    
         
            +
              return "end";
         
     | 
| 
      
 1033 
     | 
    
         
            +
                case RUBY_EVENT_CALL:
         
     | 
| 
      
 1034 
     | 
    
         
            +
              return "call";
         
     | 
| 
      
 1035 
     | 
    
         
            +
                case RUBY_EVENT_RETURN:
         
     | 
| 
      
 1036 
     | 
    
         
            +
              return "return";
         
     | 
| 
      
 1037 
     | 
    
         
            +
                case RUBY_EVENT_C_CALL:
         
     | 
| 
      
 1038 
     | 
    
         
            +
              return "c-call";
         
     | 
| 
      
 1039 
     | 
    
         
            +
                case RUBY_EVENT_C_RETURN:
         
     | 
| 
      
 1040 
     | 
    
         
            +
              return "c-return";
         
     | 
| 
      
 1041 
     | 
    
         
            +
                case RUBY_EVENT_RAISE:
         
     | 
| 
      
 1042 
     | 
    
         
            +
              return "raise";
         
     | 
| 
      
 1043 
     | 
    
         
            +
              
         
     | 
| 
      
 1044 
     | 
    
         
            +
            #ifdef RUBY_VM
         
     | 
| 
      
 1045 
     | 
    
         
            +
                case RUBY_EVENT_SWITCH:
         
     | 
| 
      
 1046 
     | 
    
         
            +
              return "thread-interrupt";
         
     | 
| 
      
 1047 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1048 
     | 
    
         
            +
              
         
     | 
| 
      
 1049 
     | 
    
         
            +
                default:
         
     | 
| 
      
 1050 
     | 
    
         
            +
              return "unknown";
         
     | 
| 
      
 1051 
     | 
    
         
            +
              }
         
     | 
| 
      
 1052 
     | 
    
         
            +
            }
         
     | 
| 
      
 1053 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1054 
     | 
    
         
            +
             
     | 
| 
      
 1055 
     | 
    
         
            +
            static prof_method_t* 
         
     | 
| 
      
 1056 
     | 
    
         
            +
            #ifdef RUBY_VM
         
     | 
| 
      
 1057 
     | 
    
         
            +
             get_method(rb_event_flag_t event, VALUE klass, ID mid, int depth, st_table* method_table)
         
     | 
| 
      
 1058 
     | 
    
         
            +
            # else
         
     | 
| 
      
 1059 
     | 
    
         
            +
             get_method(rb_event_flag_t event, NODE *node, VALUE klass, ID mid, int depth, st_table* method_table)
         
     | 
| 
      
 1060 
     | 
    
         
            +
            #endif 
         
     | 
| 
      
 1061 
     | 
    
         
            +
            {
         
     | 
| 
      
 1062 
     | 
    
         
            +
                prof_method_key_t key;
         
     | 
| 
      
 1063 
     | 
    
         
            +
                prof_method_t *method = NULL;
         
     | 
| 
      
 1064 
     | 
    
         
            +
                
         
     | 
| 
      
 1065 
     | 
    
         
            +
                method_key(&key, klass, mid, depth);
         
     | 
| 
      
 1066 
     | 
    
         
            +
                method = method_table_lookup(method_table, &key);
         
     | 
| 
      
 1067 
     | 
    
         
            +
             
     | 
| 
      
 1068 
     | 
    
         
            +
                if (!method)
         
     | 
| 
      
 1069 
     | 
    
         
            +
                {
         
     | 
| 
      
 1070 
     | 
    
         
            +
                  const char* source_file = rb_sourcefile();
         
     | 
| 
      
 1071 
     | 
    
         
            +
                  int line = rb_sourceline();
         
     | 
| 
      
 1072 
     | 
    
         
            +
                  
         
     | 
| 
      
 1073 
     | 
    
         
            +
                  /* Line numbers are not accurate for c method calls */
         
     | 
| 
      
 1074 
     | 
    
         
            +
                  if (event == RUBY_EVENT_C_CALL)
         
     | 
| 
      
 1075 
     | 
    
         
            +
                  {
         
     | 
| 
      
 1076 
     | 
    
         
            +
                    line = 0;
         
     | 
| 
      
 1077 
     | 
    
         
            +
                    source_file = NULL;
         
     | 
| 
      
 1078 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1079 
     | 
    
         
            +
                    
         
     | 
| 
      
 1080 
     | 
    
         
            +
                  method = prof_method_create(&key, source_file, line);
         
     | 
| 
      
 1081 
     | 
    
         
            +
                  method_table_insert(method_table, method->key, method);
         
     | 
| 
      
 1082 
     | 
    
         
            +
                }
         
     | 
| 
      
 1083 
     | 
    
         
            +
                return method;
         
     | 
| 
      
 1084 
     | 
    
         
            +
            }
         
     | 
| 
      
 1085 
     | 
    
         
            +
             
     | 
| 
      
 1086 
     | 
    
         
            +
            static void
         
     | 
| 
      
 1087 
     | 
    
         
            +
            update_result(prof_measure_t total_time,
         
     | 
| 
      
 1088 
     | 
    
         
            +
                          prof_frame_t *parent_frame, 
         
     | 
| 
      
 1089 
     | 
    
         
            +
                          prof_frame_t *frame)
         
     | 
| 
      
 1090 
     | 
    
         
            +
            {
         
     | 
| 
      
 1091 
     | 
    
         
            +
                prof_measure_t self_time = total_time - frame->child_time - frame->wait_time;
         
     | 
| 
      
 1092 
     | 
    
         
            +
                prof_call_info_t *call_info = frame->call_info;
         
     | 
| 
      
 1093 
     | 
    
         
            +
                
         
     | 
| 
      
 1094 
     | 
    
         
            +
                /* Update information about the current method */
         
     | 
| 
      
 1095 
     | 
    
         
            +
                call_info->called++;
         
     | 
| 
      
 1096 
     | 
    
         
            +
                call_info->total_time += total_time;
         
     | 
| 
      
 1097 
     | 
    
         
            +
                call_info->self_time += self_time;
         
     | 
| 
      
 1098 
     | 
    
         
            +
                call_info->wait_time += frame->wait_time;
         
     | 
| 
      
 1099 
     | 
    
         
            +
                
         
     | 
| 
      
 1100 
     | 
    
         
            +
                /* Note where the current method was called from */
         
     | 
| 
      
 1101 
     | 
    
         
            +
                if (parent_frame)
         
     | 
| 
      
 1102 
     | 
    
         
            +
                  call_info->line = parent_frame->line;
         
     | 
| 
      
 1103 
     | 
    
         
            +
            }
         
     | 
| 
      
 1104 
     | 
    
         
            +
             
     | 
| 
      
 1105 
     | 
    
         
            +
            static thread_data_t *
         
     | 
| 
      
 1106 
     | 
    
         
            +
            switch_thread(VALUE thread_id, prof_measure_t now)
         
     | 
| 
      
 1107 
     | 
    
         
            +
            {
         
     | 
| 
      
 1108 
     | 
    
         
            +
                prof_frame_t *frame = NULL;
         
     | 
| 
      
 1109 
     | 
    
         
            +
                prof_measure_t wait_time = 0;
         
     | 
| 
      
 1110 
     | 
    
         
            +
                /* Get new thread information. */
         
     | 
| 
      
 1111 
     | 
    
         
            +
                thread_data_t *thread_data = threads_table_lookup(threads_tbl, thread_id);
         
     | 
| 
      
 1112 
     | 
    
         
            +
             
     | 
| 
      
 1113 
     | 
    
         
            +
                /* How long has this thread been waiting? */
         
     | 
| 
      
 1114 
     | 
    
         
            +
                wait_time = now - thread_data->last_switch;
         
     | 
| 
      
 1115 
     | 
    
         
            +
                
         
     | 
| 
      
 1116 
     | 
    
         
            +
                thread_data->last_switch = now; // XXXX a test that fails if this is 0
         
     | 
| 
      
 1117 
     | 
    
         
            +
             
     | 
| 
      
 1118 
     | 
    
         
            +
                /* Get the frame at the top of the stack.  This may represent
         
     | 
| 
      
 1119 
     | 
    
         
            +
                   the current method (EVENT_LINE, EVENT_RETURN)  or the
         
     | 
| 
      
 1120 
     | 
    
         
            +
                   previous method (EVENT_CALL).*/
         
     | 
| 
      
 1121 
     | 
    
         
            +
                frame = stack_peek(thread_data->stack);
         
     | 
| 
      
 1122 
     | 
    
         
            +
              
         
     | 
| 
      
 1123 
     | 
    
         
            +
                if (frame) {
         
     | 
| 
      
 1124 
     | 
    
         
            +
                  frame->wait_time += wait_time;
         
     | 
| 
      
 1125 
     | 
    
         
            +
                }
         
     | 
| 
      
 1126 
     | 
    
         
            +
                  
         
     | 
| 
      
 1127 
     | 
    
         
            +
                /* Save on the last thread the time of the context switch
         
     | 
| 
      
 1128 
     | 
    
         
            +
                   and reset this thread's last context switch to 0.*/
         
     | 
| 
      
 1129 
     | 
    
         
            +
                if (last_thread_data) {
         
     | 
| 
      
 1130 
     | 
    
         
            +
                  last_thread_data->last_switch = now;   
         
     | 
| 
      
 1131 
     | 
    
         
            +
                }
         
     | 
| 
      
 1132 
     | 
    
         
            +
                  
         
     | 
| 
      
 1133 
     | 
    
         
            +
                last_thread_data = thread_data;
         
     | 
| 
      
 1134 
     | 
    
         
            +
                return thread_data;
         
     | 
| 
      
 1135 
     | 
    
         
            +
            }
         
     | 
| 
      
 1136 
     | 
    
         
            +
             
     | 
| 
      
 1137 
     | 
    
         
            +
            static prof_frame_t*
         
     | 
| 
      
 1138 
     | 
    
         
            +
            pop_frame(thread_data_t *thread_data, prof_measure_t now)
         
     | 
| 
      
 1139 
     | 
    
         
            +
            {
         
     | 
| 
      
 1140 
     | 
    
         
            +
              prof_frame_t *frame = NULL;
         
     | 
| 
      
 1141 
     | 
    
         
            +
              prof_frame_t* parent_frame = NULL;
         
     | 
| 
      
 1142 
     | 
    
         
            +
              prof_measure_t total_time;
         
     | 
| 
      
 1143 
     | 
    
         
            +
             
     | 
| 
      
 1144 
     | 
    
         
            +
              frame = stack_pop(thread_data->stack); // only time it's called
         
     | 
| 
      
 1145 
     | 
    
         
            +
              /* Frame can be null.  This can happen if RubProf.start is called from
         
     | 
| 
      
 1146 
     | 
    
         
            +
                 a method that exits.  And it can happen if an exception is raised
         
     | 
| 
      
 1147 
     | 
    
         
            +
                 in code that is being profiled and the stack unwinds (RubyProf is
         
     | 
| 
      
 1148 
     | 
    
         
            +
                 not notified of that by the ruby runtime. */
         
     | 
| 
      
 1149 
     | 
    
         
            +
              if (frame == NULL) return NULL;
         
     | 
| 
      
 1150 
     | 
    
         
            +
             
     | 
| 
      
 1151 
     | 
    
         
            +
              /* Calculate the total time this method took */
         
     | 
| 
      
 1152 
     | 
    
         
            +
              total_time = now - frame->start_time;
         
     | 
| 
      
 1153 
     | 
    
         
            +
             
     | 
| 
      
 1154 
     | 
    
         
            +
              /* Now deactivate the method */
         
     | 
| 
      
 1155 
     | 
    
         
            +
              frame->call_info->target->active = 0;
         
     | 
| 
      
 1156 
     | 
    
         
            +
             
     | 
| 
      
 1157 
     | 
    
         
            +
              parent_frame = stack_peek(thread_data->stack);
         
     | 
| 
      
 1158 
     | 
    
         
            +
              if (parent_frame)
         
     | 
| 
      
 1159 
     | 
    
         
            +
              {
         
     | 
| 
      
 1160 
     | 
    
         
            +
                  parent_frame->child_time += total_time;
         
     | 
| 
      
 1161 
     | 
    
         
            +
              }
         
     | 
| 
      
 1162 
     | 
    
         
            +
                
         
     | 
| 
      
 1163 
     | 
    
         
            +
              update_result(total_time, parent_frame, frame); // only time it's called
         
     | 
| 
      
 1164 
     | 
    
         
            +
              return frame;
         
     | 
| 
      
 1165 
     | 
    
         
            +
            }
         
     | 
| 
      
 1166 
     | 
    
         
            +
             
     | 
| 
      
 1167 
     | 
    
         
            +
            static int 
         
     | 
| 
      
 1168 
     | 
    
         
            +
            pop_frames(st_data_t key, st_data_t value, st_data_t now_arg)
         
     | 
| 
      
 1169 
     | 
    
         
            +
            {
         
     | 
| 
      
 1170 
     | 
    
         
            +
                VALUE thread_id = (VALUE)key;
         
     | 
| 
      
 1171 
     | 
    
         
            +
                thread_data_t* thread_data = (thread_data_t *) value;
         
     | 
| 
      
 1172 
     | 
    
         
            +
                prof_measure_t now = *(prof_measure_t *) now_arg;
         
     | 
| 
      
 1173 
     | 
    
         
            +
             
     | 
| 
      
 1174 
     | 
    
         
            +
                if (!last_thread_data || last_thread_data->thread_id != thread_id)
         
     | 
| 
      
 1175 
     | 
    
         
            +
                  thread_data = switch_thread(thread_id, now);
         
     | 
| 
      
 1176 
     | 
    
         
            +
                else
         
     | 
| 
      
 1177 
     | 
    
         
            +
                  thread_data = last_thread_data;
         
     | 
| 
      
 1178 
     | 
    
         
            +
             
     | 
| 
      
 1179 
     | 
    
         
            +
                while (pop_frame(thread_data, now))
         
     | 
| 
      
 1180 
     | 
    
         
            +
                {
         
     | 
| 
      
 1181 
     | 
    
         
            +
                }
         
     | 
| 
      
 1182 
     | 
    
         
            +
                
         
     | 
| 
      
 1183 
     | 
    
         
            +
                return ST_CONTINUE;
         
     | 
| 
      
 1184 
     | 
    
         
            +
            }
         
     | 
| 
      
 1185 
     | 
    
         
            +
             
     | 
| 
      
 1186 
     | 
    
         
            +
            static void 
         
     | 
| 
      
 1187 
     | 
    
         
            +
            prof_pop_threads()
         
     | 
| 
      
 1188 
     | 
    
         
            +
            {
         
     | 
| 
      
 1189 
     | 
    
         
            +
                /* Get current measurement */
         
     | 
| 
      
 1190 
     | 
    
         
            +
                prof_measure_t now = get_measurement();
         
     | 
| 
      
 1191 
     | 
    
         
            +
                st_foreach(threads_tbl,  pop_frames, (st_data_t) &now);
         
     | 
| 
      
 1192 
     | 
    
         
            +
            }
         
     | 
| 
      
 1193 
     | 
    
         
            +
             
     | 
| 
      
 1194 
     | 
    
         
            +
             
     | 
| 
      
 1195 
     | 
    
         
            +
             
     | 
| 
      
 1196 
     | 
    
         
            +
             
     | 
| 
      
 1197 
     | 
    
         
            +
            #ifdef RUBY_VM
         
     | 
| 
      
 1198 
     | 
    
         
            +
             
     | 
| 
      
 1199 
     | 
    
         
            +
            /* These are mostly to avoid bugs in core */
         
     | 
| 
      
 1200 
     | 
    
         
            +
            static inline void walk_up_until_right_frame(prof_frame_t *frame, thread_data_t* thread_data, ID mid, VALUE klass, prof_measure_t now);
         
     | 
| 
      
 1201 
     | 
    
         
            +
            void prof_install_hook();
         
     | 
| 
      
 1202 
     | 
    
         
            +
            void prof_remove_hook();
         
     | 
| 
      
 1203 
     | 
    
         
            +
             
     | 
| 
      
 1204 
     | 
    
         
            +
            static void
         
     | 
| 
      
 1205 
     | 
    
         
            +
            prof_event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE klass)
         
     | 
| 
      
 1206 
     | 
    
         
            +
            #else
         
     | 
| 
      
 1207 
     | 
    
         
            +
            static void
         
     | 
| 
      
 1208 
     | 
    
         
            +
            prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass)
         
     | 
| 
      
 1209 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1210 
     | 
    
         
            +
            {
         
     | 
| 
      
 1211 
     | 
    
         
            +
                
         
     | 
| 
      
 1212 
     | 
    
         
            +
                VALUE thread = Qnil;
         
     | 
| 
      
 1213 
     | 
    
         
            +
                VALUE thread_id = Qnil;
         
     | 
| 
      
 1214 
     | 
    
         
            +
                prof_measure_t now = 0;
         
     | 
| 
      
 1215 
     | 
    
         
            +
                thread_data_t* thread_data = NULL;
         
     | 
| 
      
 1216 
     | 
    
         
            +
                prof_frame_t *frame = NULL;
         
     | 
| 
      
 1217 
     | 
    
         
            +
             
     | 
| 
      
 1218 
     | 
    
         
            +
                #ifdef RUBY_VM
         
     | 
| 
      
 1219 
     | 
    
         
            +
                  if (event != RUBY_EVENT_C_CALL && event != RUBY_EVENT_C_RETURN) {
         
     | 
| 
      
 1220 
     | 
    
         
            +
                    // guess these are already set for C calls in 1.9, then?
         
     | 
| 
      
 1221 
     | 
    
         
            +
                    rb_frame_method_id_and_class(&mid, &klass);
         
     | 
| 
      
 1222 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1223 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1224 
     | 
    
         
            +
             
     | 
| 
      
 1225 
     | 
    
         
            +
                /* Get current timestamp */
         
     | 
| 
      
 1226 
     | 
    
         
            +
                now = get_measurement();
         
     | 
| 
      
 1227 
     | 
    
         
            +
             
     | 
| 
      
 1228 
     | 
    
         
            +
            #ifdef DEBUG
         
     | 
| 
      
 1229 
     | 
    
         
            +
                /*  This code is here for debug purposes - uncomment it out
         
     | 
| 
      
 1230 
     | 
    
         
            +
                    when debugging to see a print out of exactly what the
         
     | 
| 
      
 1231 
     | 
    
         
            +
                    profiler is tracing. */
         
     | 
| 
      
 1232 
     | 
    
         
            +
                {
         
     | 
| 
      
 1233 
     | 
    
         
            +
                    static VALUE last_thread_id = Qnil;
         
     | 
| 
      
 1234 
     | 
    
         
            +
             
     | 
| 
      
 1235 
     | 
    
         
            +
                    VALUE thread = rb_thread_current();
         
     | 
| 
      
 1236 
     | 
    
         
            +
                    VALUE thread_id = rb_obj_id(thread);
         
     | 
| 
      
 1237 
     | 
    
         
            +
                    const char* class_name = NULL;
         
     | 
| 
      
 1238 
     | 
    
         
            +
                    const char* method_name = rb_id2name(mid);
         
     | 
| 
      
 1239 
     | 
    
         
            +
                    const char* source_file = rb_sourcefile();
         
     | 
| 
      
 1240 
     | 
    
         
            +
                    unsigned int source_line = rb_sourceline();
         
     | 
| 
      
 1241 
     | 
    
         
            +
             
     | 
| 
      
 1242 
     | 
    
         
            +
                    char* event_name = get_event_name(event);
         
     | 
| 
      
 1243 
     | 
    
         
            +
             
     | 
| 
      
 1244 
     | 
    
         
            +
                    if (klass != 0)
         
     | 
| 
      
 1245 
     | 
    
         
            +
                      klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
         
     | 
| 
      
 1246 
     | 
    
         
            +
             
     | 
| 
      
 1247 
     | 
    
         
            +
                    class_name = rb_class2name(klass);
         
     | 
| 
      
 1248 
     | 
    
         
            +
             
     | 
| 
      
 1249 
     | 
    
         
            +
                    if (last_thread_id != thread_id) {
         
     | 
| 
      
 1250 
     | 
    
         
            +
                      printf("\n");
         
     | 
| 
      
 1251 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1252 
     | 
    
         
            +
                    
         
     | 
| 
      
 1253 
     | 
    
         
            +
                    printf("%2u:%2ums %-8s %s:%2d  %s#%s\n",
         
     | 
| 
      
 1254 
     | 
    
         
            +
                           (unsigned int) thread_id, (unsigned int) now, event_name, source_file, source_line, class_name, method_name);
         
     | 
| 
      
 1255 
     | 
    
         
            +
                    fflush(stdout);
         
     | 
| 
      
 1256 
     | 
    
         
            +
                    last_thread_id = thread_id;               
         
     | 
| 
      
 1257 
     | 
    
         
            +
                }
         
     | 
| 
      
 1258 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1259 
     | 
    
         
            +
                if (call_tree_profile_on) 
         
     | 
| 
      
 1260 
     | 
    
         
            +
                {
         
     | 
| 
      
 1261 
     | 
    
         
            +
                   call_tree_prof_event_hook(event, node, self, mid, klass);
         
     | 
| 
      
 1262 
     | 
    
         
            +
                   return;
         
     | 
| 
      
 1263 
     | 
    
         
            +
                }
         
     | 
| 
      
 1264 
     | 
    
         
            +
                
         
     | 
| 
      
 1265 
     | 
    
         
            +
                /* Special case - skip any methods from the mProf 
         
     | 
| 
      
 1266 
     | 
    
         
            +
                   module, such as Prof.stop, since they clutter
         
     | 
| 
      
 1267 
     | 
    
         
            +
                   the results but aren't important to them results. */
         
     | 
| 
      
 1268 
     | 
    
         
            +
                if (self == mProf) return;
         
     | 
| 
      
 1269 
     | 
    
         
            +
             
     | 
| 
      
 1270 
     | 
    
         
            +
                /* Get the current thread information. */
         
     | 
| 
      
 1271 
     | 
    
         
            +
                thread = rb_thread_current();
         
     | 
| 
      
 1272 
     | 
    
         
            +
                thread_id = rb_obj_id(thread);
         
     | 
| 
      
 1273 
     | 
    
         
            +
                
         
     | 
| 
      
 1274 
     | 
    
         
            +
               # ifdef RUBY_VM
         
     | 
| 
      
 1275 
     | 
    
         
            +
                 /* ensure that new threads are hooked [sigh] (bug in core) */
         
     | 
| 
      
 1276 
     | 
    
         
            +
                 prof_remove_hook();
         
     | 
| 
      
 1277 
     | 
    
         
            +
                 prof_install_hook();
         
     | 
| 
      
 1278 
     | 
    
         
            +
               # endif
         
     | 
| 
      
 1279 
     | 
    
         
            +
             
     | 
| 
      
 1280 
     | 
    
         
            +
                if (exclude_threads_tbl &&
         
     | 
| 
      
 1281 
     | 
    
         
            +
                    st_lookup(exclude_threads_tbl, (st_data_t) thread_id, 0)) 
         
     | 
| 
      
 1282 
     | 
    
         
            +
                {
         
     | 
| 
      
 1283 
     | 
    
         
            +
                  return;
         
     | 
| 
      
 1284 
     | 
    
         
            +
                }    
         
     | 
| 
      
 1285 
     | 
    
         
            +
                
         
     | 
| 
      
 1286 
     | 
    
         
            +
                
         
     | 
| 
      
 1287 
     | 
    
         
            +
                /* Was there a context switch? */
         
     | 
| 
      
 1288 
     | 
    
         
            +
                if (!last_thread_data || last_thread_data->thread_id != thread_id)
         
     | 
| 
      
 1289 
     | 
    
         
            +
                  thread_data = switch_thread(thread_id, now);
         
     | 
| 
      
 1290 
     | 
    
         
            +
                else
         
     | 
| 
      
 1291 
     | 
    
         
            +
                  thread_data = last_thread_data;
         
     | 
| 
      
 1292 
     | 
    
         
            +
                
         
     | 
| 
      
 1293 
     | 
    
         
            +
                
         
     | 
| 
      
 1294 
     | 
    
         
            +
                switch (event) {
         
     | 
| 
      
 1295 
     | 
    
         
            +
                case RUBY_EVENT_LINE:
         
     | 
| 
      
 1296 
     | 
    
         
            +
                {
         
     | 
| 
      
 1297 
     | 
    
         
            +
                  /* Keep track of the current line number in this method.  When
         
     | 
| 
      
 1298 
     | 
    
         
            +
                     a new method is called, we know what line number it was 
         
     | 
| 
      
 1299 
     | 
    
         
            +
                     called from. */
         
     | 
| 
      
 1300 
     | 
    
         
            +
                     
         
     | 
| 
      
 1301 
     | 
    
         
            +
                   /* Get the current frame for the current thread. */
         
     | 
| 
      
 1302 
     | 
    
         
            +
                  frame = stack_peek(thread_data->stack);
         
     | 
| 
      
 1303 
     | 
    
         
            +
             
     | 
| 
      
 1304 
     | 
    
         
            +
                  if (frame)
         
     | 
| 
      
 1305 
     | 
    
         
            +
                  {
         
     | 
| 
      
 1306 
     | 
    
         
            +
                    frame->line = rb_sourceline();        
         
     | 
| 
      
 1307 
     | 
    
         
            +
                    
         
     | 
| 
      
 1308 
     | 
    
         
            +
                    # ifdef RUBY_VM
         
     | 
| 
      
 1309 
     | 
    
         
            +
                      // disabled till I figure out why it causes
         
     | 
| 
      
 1310 
     | 
    
         
            +
                      // us to lose valuable frame information...maybe mid comes in wrong sometimes?
         
     | 
| 
      
 1311 
     | 
    
         
            +
                      // walk_up_until_right_frame(frame, thread_data, mid, klass, now);
         
     | 
| 
      
 1312 
     | 
    
         
            +
                    # endif
         
     | 
| 
      
 1313 
     | 
    
         
            +
                    
         
     | 
| 
      
 1314 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1315 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1316 
     | 
    
         
            +
             
     | 
| 
      
 1317 
     | 
    
         
            +
                  /* If we get here there was no frame, which means this is 
         
     | 
| 
      
 1318 
     | 
    
         
            +
                     the first method seen for this thread, so fall through
         
     | 
| 
      
 1319 
     | 
    
         
            +
                     to below to create it. */
         
     | 
| 
      
 1320 
     | 
    
         
            +
                }
         
     | 
| 
      
 1321 
     | 
    
         
            +
                case RUBY_EVENT_CALL:
         
     | 
| 
      
 1322 
     | 
    
         
            +
                case RUBY_EVENT_C_CALL:
         
     | 
| 
      
 1323 
     | 
    
         
            +
                {
         
     | 
| 
      
 1324 
     | 
    
         
            +
                    prof_call_info_t *call_info = NULL;
         
     | 
| 
      
 1325 
     | 
    
         
            +
                    prof_method_t *method = NULL;
         
     | 
| 
      
 1326 
     | 
    
         
            +
             
     | 
| 
      
 1327 
     | 
    
         
            +
                    /* Get the current frame for the current thread. */
         
     | 
| 
      
 1328 
     | 
    
         
            +
                    frame = stack_peek(thread_data->stack);
         
     | 
| 
      
 1329 
     | 
    
         
            +
             
     | 
| 
      
 1330 
     | 
    
         
            +
                    /* Is this an include for a module?  If so get the actual
         
     | 
| 
      
 1331 
     | 
    
         
            +
                       module class since we want to combine all profiling
         
     | 
| 
      
 1332 
     | 
    
         
            +
                       results for that module. */
         
     | 
| 
      
 1333 
     | 
    
         
            +
                    
         
     | 
| 
      
 1334 
     | 
    
         
            +
                    if (klass != 0)
         
     | 
| 
      
 1335 
     | 
    
         
            +
                      klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
         
     | 
| 
      
 1336 
     | 
    
         
            +
                      
         
     | 
| 
      
 1337 
     | 
    
         
            +
                    /* Assume this is the first time we have called this method. */
         
     | 
| 
      
 1338 
     | 
    
         
            +
                    #ifdef RUBY_VM
         
     | 
| 
      
 1339 
     | 
    
         
            +
                      method = get_method(event, klass, mid, 0, thread_data->method_table);
         
     | 
| 
      
 1340 
     | 
    
         
            +
                    #else
         
     | 
| 
      
 1341 
     | 
    
         
            +
                      method = get_method(event, node, klass, mid, 0, thread_data->method_table);
         
     | 
| 
      
 1342 
     | 
    
         
            +
                    #endif
         
     | 
| 
      
 1343 
     | 
    
         
            +
                    /* Check for a recursive call */
         
     | 
| 
      
 1344 
     | 
    
         
            +
                    while (method->active) // it's while because we start at 0 and then inc. to the right recursive depth
         
     | 
| 
      
 1345 
     | 
    
         
            +
                    {
         
     | 
| 
      
 1346 
     | 
    
         
            +
                      /* Yes, this method is already active somewhere up the stack */
         
     | 
| 
      
 1347 
     | 
    
         
            +
                      #ifdef RUBY_VM
         
     | 
| 
      
 1348 
     | 
    
         
            +
                        method = get_method(event, klass, mid, method->key->depth + 1, thread_data->method_table);
         
     | 
| 
      
 1349 
     | 
    
         
            +
                      #else
         
     | 
| 
      
 1350 
     | 
    
         
            +
                        method = get_method(event, node, klass, mid, method->key->depth + 1, thread_data->method_table);
         
     | 
| 
      
 1351 
     | 
    
         
            +
                      #endif
         
     | 
| 
      
 1352 
     | 
    
         
            +
                    }          
         
     | 
| 
      
 1353 
     | 
    
         
            +
                    method->active = 1;                
         
     | 
| 
      
 1354 
     | 
    
         
            +
             
     | 
| 
      
 1355 
     | 
    
         
            +
                    if (!frame)
         
     | 
| 
      
 1356 
     | 
    
         
            +
                    {
         
     | 
| 
      
 1357 
     | 
    
         
            +
                      call_info = prof_call_info_create(method, NULL);
         
     | 
| 
      
 1358 
     | 
    
         
            +
                      prof_add_call_info(method->call_infos, call_info);
         
     | 
| 
      
 1359 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1360 
     | 
    
         
            +
                    else
         
     | 
| 
      
 1361 
     | 
    
         
            +
                    {
         
     | 
| 
      
 1362 
     | 
    
         
            +
                      call_info = call_info_table_lookup(frame->call_info->call_infos, method->key);
         
     | 
| 
      
 1363 
     | 
    
         
            +
             
     | 
| 
      
 1364 
     | 
    
         
            +
                      if (!call_info)
         
     | 
| 
      
 1365 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1366 
     | 
    
         
            +
                        call_info = prof_call_info_create(method, frame->call_info);
         
     | 
| 
      
 1367 
     | 
    
         
            +
                        call_info_table_insert(frame->call_info->call_infos, method->key, call_info);
         
     | 
| 
      
 1368 
     | 
    
         
            +
                        prof_add_call_info(method->call_infos, call_info);
         
     | 
| 
      
 1369 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1370 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1371 
     | 
    
         
            +
             
     | 
| 
      
 1372 
     | 
    
         
            +
                    /* Push a new frame onto the stack for a new c-call or ruby call (into a method) */
         
     | 
| 
      
 1373 
     | 
    
         
            +
                    frame = stack_push(thread_data->stack);
         
     | 
| 
      
 1374 
     | 
    
         
            +
                    frame->call_info = call_info;
         
     | 
| 
      
 1375 
     | 
    
         
            +
                    frame->start_time = now;
         
     | 
| 
      
 1376 
     | 
    
         
            +
                    frame->wait_time = 0;
         
     | 
| 
      
 1377 
     | 
    
         
            +
                    frame->child_time = 0;
         
     | 
| 
      
 1378 
     | 
    
         
            +
                    frame->line = rb_sourceline();
         
     | 
| 
      
 1379 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1380 
     | 
    
         
            +
                }
         
     | 
| 
      
 1381 
     | 
    
         
            +
                case RUBY_EVENT_RETURN:
         
     | 
| 
      
 1382 
     | 
    
         
            +
                case RUBY_EVENT_C_RETURN:
         
     | 
| 
      
 1383 
     | 
    
         
            +
                {      
         
     | 
| 
      
 1384 
     | 
    
         
            +
                    frame = pop_frame(thread_data, now);
         
     | 
| 
      
 1385 
     | 
    
         
            +
                  
         
     | 
| 
      
 1386 
     | 
    
         
            +
                  # ifdef RUBY_VM
         
     | 
| 
      
 1387 
     | 
    
         
            +
                    // we need to walk up the stack to find the right one [http://redmine.ruby-lang.org/issues/show/2610] (for now)
         
     | 
| 
      
 1388 
     | 
    
         
            +
                    // sometimes frames don't have line and source somehow [like blank]
         
     | 
| 
      
 1389 
     | 
    
         
            +
                    // if we hit one there's not much we can do...I guess...
         
     | 
| 
      
 1390 
     | 
    
         
            +
                    // or maybe we don't have one because we're at the top or something.
         
     | 
| 
      
 1391 
     | 
    
         
            +
                    walk_up_until_right_frame(frame, thread_data, mid, klass, now);
         
     | 
| 
      
 1392 
     | 
    
         
            +
                  # endif
         
     | 
| 
      
 1393 
     | 
    
         
            +
                            
         
     | 
| 
      
 1394 
     | 
    
         
            +
                  break;
         
     | 
| 
      
 1395 
     | 
    
         
            +
                }
         
     | 
| 
      
 1396 
     | 
    
         
            +
                }
         
     | 
| 
      
 1397 
     | 
    
         
            +
            }
         
     | 
| 
      
 1398 
     | 
    
         
            +
             
     | 
| 
      
 1399 
     | 
    
         
            +
            #ifdef RUBY_VM
         
     | 
| 
      
 1400 
     | 
    
         
            +
             
     | 
| 
      
 1401 
     | 
    
         
            +
            static inline void walk_up_until_right_frame(prof_frame_t *frame, thread_data_t* thread_data, ID mid, VALUE klass, prof_measure_t now) {
         
     | 
| 
      
 1402 
     | 
    
         
            +
              // while it doesn't match, pop on up until we have found where we belong...
         
     | 
| 
      
 1403 
     | 
    
         
            +
              while( frame && frame->call_info->target->key->mid && frame->call_info->target->key->klass && ((frame->call_info->target->key->mid != mid) || (frame->call_info->target->key->klass != klass))){
         
     | 
| 
      
 1404 
     | 
    
         
            +
                frame = pop_frame(thread_data, now);
         
     | 
| 
      
 1405 
     | 
    
         
            +
              }
         
     | 
| 
      
 1406 
     | 
    
         
            +
            }
         
     | 
| 
      
 1407 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1408 
     | 
    
         
            +
             
     | 
| 
      
 1409 
     | 
    
         
            +
            /* ========  ProfResult ============== */
         
     | 
| 
      
 1410 
     | 
    
         
            +
             
     | 
| 
      
 1411 
     | 
    
         
            +
            /* Document-class: RubyProf::Result
         
     | 
| 
      
 1412 
     | 
    
         
            +
            The RubyProf::Result class is used to store the results of a 
         
     | 
| 
      
 1413 
     | 
    
         
            +
            profiling run.  And instace of the class is returned from
         
     | 
| 
      
 1414 
     | 
    
         
            +
            the methods RubyProf#stop and RubyProf#profile.
         
     | 
| 
      
 1415 
     | 
    
         
            +
             
     | 
| 
      
 1416 
     | 
    
         
            +
            RubyProf::Result has one field, called threads, which is a hash
         
     | 
| 
      
 1417 
     | 
    
         
            +
            table keyed on thread ID.  For each thread id, the hash table
         
     | 
| 
      
 1418 
     | 
    
         
            +
            stores another hash table that contains profiling information
         
     | 
| 
      
 1419 
     | 
    
         
            +
            for each method called during the threads execution.  That
         
     | 
| 
      
 1420 
     | 
    
         
            +
            hash table is keyed on method name and contains
         
     | 
| 
      
 1421 
     | 
    
         
            +
            RubyProf::MethodInfo objects. */
         
     | 
| 
      
 1422 
     | 
    
         
            +
             
     | 
| 
      
 1423 
     | 
    
         
            +
            static void
         
     | 
| 
      
 1424 
     | 
    
         
            +
            prof_result_mark(prof_result_t *prof_result)
         
     | 
| 
      
 1425 
     | 
    
         
            +
            {
         
     | 
| 
      
 1426 
     | 
    
         
            +
                VALUE threads = prof_result->threads;
         
     | 
| 
      
 1427 
     | 
    
         
            +
                rb_gc_mark(threads);
         
     | 
| 
      
 1428 
     | 
    
         
            +
            }
         
     | 
| 
      
 1429 
     | 
    
         
            +
             
     | 
| 
      
 1430 
     | 
    
         
            +
            static void
         
     | 
| 
      
 1431 
     | 
    
         
            +
            prof_result_free(prof_result_t *prof_result)
         
     | 
| 
      
 1432 
     | 
    
         
            +
            {
         
     | 
| 
      
 1433 
     | 
    
         
            +
                prof_result->threads = Qnil;
         
     | 
| 
      
 1434 
     | 
    
         
            +
                xfree(prof_result);
         
     | 
| 
      
 1435 
     | 
    
         
            +
            }
         
     | 
| 
      
 1436 
     | 
    
         
            +
             
     | 
| 
      
 1437 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1438 
     | 
    
         
            +
            prof_result_new()
         
     | 
| 
      
 1439 
     | 
    
         
            +
            {
         
     | 
| 
      
 1440 
     | 
    
         
            +
                prof_result_t *prof_result = ALLOC(prof_result_t);
         
     | 
| 
      
 1441 
     | 
    
         
            +
             
     | 
| 
      
 1442 
     | 
    
         
            +
                /* Wrap threads in Ruby regular Ruby hash table. */
         
     | 
| 
      
 1443 
     | 
    
         
            +
                prof_result->threads = rb_hash_new();
         
     | 
| 
      
 1444 
     | 
    
         
            +
                st_foreach(threads_tbl, collect_threads, prof_result->threads);
         
     | 
| 
      
 1445 
     | 
    
         
            +
             
     | 
| 
      
 1446 
     | 
    
         
            +
                return Data_Wrap_Struct(cResult, prof_result_mark, prof_result_free, prof_result);
         
     | 
| 
      
 1447 
     | 
    
         
            +
            }
         
     | 
| 
      
 1448 
     | 
    
         
            +
             
     | 
| 
      
 1449 
     | 
    
         
            +
             
     | 
| 
      
 1450 
     | 
    
         
            +
            static prof_result_t *
         
     | 
| 
      
 1451 
     | 
    
         
            +
            get_prof_result(VALUE obj)
         
     | 
| 
      
 1452 
     | 
    
         
            +
            {
         
     | 
| 
      
 1453 
     | 
    
         
            +
                if (BUILTIN_TYPE(obj) != T_DATA ||
         
     | 
| 
      
 1454 
     | 
    
         
            +
                  RDATA(obj)->dfree != (RUBY_DATA_FUNC) prof_result_free)
         
     | 
| 
      
 1455 
     | 
    
         
            +
                {
         
     | 
| 
      
 1456 
     | 
    
         
            +
                    /* Should never happen */
         
     | 
| 
      
 1457 
     | 
    
         
            +
                  rb_raise(rb_eTypeError, "wrong result object (%d %d) ", BUILTIN_TYPE(obj) != T_DATA, RDATA(obj)->dfree != (RUBY_DATA_FUNC) prof_result_free);
         
     | 
| 
      
 1458 
     | 
    
         
            +
                }
         
     | 
| 
      
 1459 
     | 
    
         
            +
                return (prof_result_t *) DATA_PTR(obj);
         
     | 
| 
      
 1460 
     | 
    
         
            +
            }
         
     | 
| 
      
 1461 
     | 
    
         
            +
             
     | 
| 
      
 1462 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1463 
     | 
    
         
            +
               threads -> Hash
         
     | 
| 
      
 1464 
     | 
    
         
            +
             
     | 
| 
      
 1465 
     | 
    
         
            +
            Returns a hash table keyed on thread ID.  For each thread id,
         
     | 
| 
      
 1466 
     | 
    
         
            +
            the hash table stores another hash table that contains profiling
         
     | 
| 
      
 1467 
     | 
    
         
            +
            information for each method called during the threads execution.
         
     | 
| 
      
 1468 
     | 
    
         
            +
            That hash table is keyed on method name and contains 
         
     | 
| 
      
 1469 
     | 
    
         
            +
            RubyProf::MethodInfo objects. */
         
     | 
| 
      
 1470 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1471 
     | 
    
         
            +
            prof_result_threads(VALUE self)
         
     | 
| 
      
 1472 
     | 
    
         
            +
            {
         
     | 
| 
      
 1473 
     | 
    
         
            +
                prof_result_t *prof_result = get_prof_result(self);
         
     | 
| 
      
 1474 
     | 
    
         
            +
                return prof_result->threads;
         
     | 
| 
      
 1475 
     | 
    
         
            +
            }
         
     | 
| 
      
 1476 
     | 
    
         
            +
             
     | 
| 
      
 1477 
     | 
    
         
            +
             
     | 
| 
      
 1478 
     | 
    
         
            +
             
     | 
| 
      
 1479 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1480 
     | 
    
         
            +
               measure_mode -> measure_mode
         
     | 
| 
      
 1481 
     | 
    
         
            +
               
         
     | 
| 
      
 1482 
     | 
    
         
            +
               Returns what ruby-prof is measuring.  Valid values include:
         
     | 
| 
      
 1483 
     | 
    
         
            +
               
         
     | 
| 
      
 1484 
     | 
    
         
            +
               *RubyProf::PROCESS_TIME - Measure process time.  This is default.  It is implemented using the clock functions in the C Runtime library.
         
     | 
| 
      
 1485 
     | 
    
         
            +
               *RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows
         
     | 
| 
      
 1486 
     | 
    
         
            +
               *RubyProf::CPU_TIME - Measure time using the CPU clock counter.  This mode is only supported on Pentium or PowerPC platforms. 
         
     | 
| 
      
 1487 
     | 
    
         
            +
               *RubyProf::ALLOCATIONS - Measure object allocations.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1488 
     | 
    
         
            +
               *RubyProf::MEMORY - Measure memory size.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1489 
     | 
    
         
            +
               *RubyProf::GC_RUNS - Measure number of garbage collections.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1490 
     | 
    
         
            +
               *RubyProf::GC_TIME - Measure time spent doing garbage collection.  This requires a patched Ruby interpreter.*/
         
     | 
| 
      
 1491 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1492 
     | 
    
         
            +
            prof_get_measure_mode(VALUE self)
         
     | 
| 
      
 1493 
     | 
    
         
            +
            {
         
     | 
| 
      
 1494 
     | 
    
         
            +
                return INT2NUM(measure_mode);
         
     | 
| 
      
 1495 
     | 
    
         
            +
            }
         
     | 
| 
      
 1496 
     | 
    
         
            +
             
     | 
| 
      
 1497 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1498 
     | 
    
         
            +
               measure_mode=value -> void
         
     | 
| 
      
 1499 
     | 
    
         
            +
               
         
     | 
| 
      
 1500 
     | 
    
         
            +
               Specifies what ruby-prof should measure.  Valid values include:
         
     | 
| 
      
 1501 
     | 
    
         
            +
               
         
     | 
| 
      
 1502 
     | 
    
         
            +
               *RubyProf::PROCESS_TIME - Measure process time.  This is default.  It is implemented using the clock functions in the C Runtime library.
         
     | 
| 
      
 1503 
     | 
    
         
            +
               *RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows
         
     | 
| 
      
 1504 
     | 
    
         
            +
               *RubyProf::CPU_TIME - Measure time using the CPU clock counter.  This mode is only supported on Pentium or PowerPC platforms. 
         
     | 
| 
      
 1505 
     | 
    
         
            +
               *RubyProf::ALLOCATIONS - Measure object allocations.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1506 
     | 
    
         
            +
               *RubyProf::MEMORY - Measure memory size.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1507 
     | 
    
         
            +
               *RubyProf::GC_RUNS - Measure number of garbage collections.  This requires a patched Ruby interpreter.
         
     | 
| 
      
 1508 
     | 
    
         
            +
               *RubyProf::GC_TIME - Measure time spent doing garbage collection.  This requires a patched Ruby interpreter.*/
         
     | 
| 
      
 1509 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1510 
     | 
    
         
            +
            prof_set_measure_mode(VALUE self, VALUE val)
         
     | 
| 
      
 1511 
     | 
    
         
            +
            {
         
     | 
| 
      
 1512 
     | 
    
         
            +
                long mode = NUM2LONG(val);
         
     | 
| 
      
 1513 
     | 
    
         
            +
             
     | 
| 
      
 1514 
     | 
    
         
            +
                if (threads_tbl)
         
     | 
| 
      
 1515 
     | 
    
         
            +
                {
         
     | 
| 
      
 1516 
     | 
    
         
            +
                  rb_raise(rb_eRuntimeError, "can't set measure_mode while profiling");
         
     | 
| 
      
 1517 
     | 
    
         
            +
                }
         
     | 
| 
      
 1518 
     | 
    
         
            +
             
     | 
| 
      
 1519 
     | 
    
         
            +
                switch (mode) {
         
     | 
| 
      
 1520 
     | 
    
         
            +
                  case MEASURE_PROCESS_TIME:
         
     | 
| 
      
 1521 
     | 
    
         
            +
                    get_measurement = measure_process_time;
         
     | 
| 
      
 1522 
     | 
    
         
            +
                    convert_measurement = convert_process_time;
         
     | 
| 
      
 1523 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1524 
     | 
    
         
            +
                    
         
     | 
| 
      
 1525 
     | 
    
         
            +
                  case MEASURE_WALL_TIME:
         
     | 
| 
      
 1526 
     | 
    
         
            +
                    get_measurement = measure_wall_time;
         
     | 
| 
      
 1527 
     | 
    
         
            +
                    convert_measurement = convert_wall_time;
         
     | 
| 
      
 1528 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1529 
     | 
    
         
            +
                    
         
     | 
| 
      
 1530 
     | 
    
         
            +
                  #if defined(MEASURE_CPU_TIME)
         
     | 
| 
      
 1531 
     | 
    
         
            +
                  case MEASURE_CPU_TIME:
         
     | 
| 
      
 1532 
     | 
    
         
            +
                    if (cpu_frequency == 0)
         
     | 
| 
      
 1533 
     | 
    
         
            +
                        cpu_frequency = get_cpu_frequency();
         
     | 
| 
      
 1534 
     | 
    
         
            +
                    get_measurement = measure_cpu_time;
         
     | 
| 
      
 1535 
     | 
    
         
            +
                    convert_measurement = convert_cpu_time;
         
     | 
| 
      
 1536 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1537 
     | 
    
         
            +
                  #endif
         
     | 
| 
      
 1538 
     | 
    
         
            +
                          
         
     | 
| 
      
 1539 
     | 
    
         
            +
                  #if defined(MEASURE_ALLOCATIONS)
         
     | 
| 
      
 1540 
     | 
    
         
            +
                  case MEASURE_ALLOCATIONS:
         
     | 
| 
      
 1541 
     | 
    
         
            +
                    get_measurement = measure_allocations;
         
     | 
| 
      
 1542 
     | 
    
         
            +
                    convert_measurement = convert_allocations;
         
     | 
| 
      
 1543 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1544 
     | 
    
         
            +
                  #endif
         
     | 
| 
      
 1545 
     | 
    
         
            +
                    
         
     | 
| 
      
 1546 
     | 
    
         
            +
                  #if defined(MEASURE_MEMORY)
         
     | 
| 
      
 1547 
     | 
    
         
            +
                  case MEASURE_MEMORY:
         
     | 
| 
      
 1548 
     | 
    
         
            +
                    get_measurement = measure_memory;
         
     | 
| 
      
 1549 
     | 
    
         
            +
                    convert_measurement = convert_memory;
         
     | 
| 
      
 1550 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1551 
     | 
    
         
            +
                  #endif
         
     | 
| 
      
 1552 
     | 
    
         
            +
             
     | 
| 
      
 1553 
     | 
    
         
            +
                  #if defined(MEASURE_GC_RUNS)
         
     | 
| 
      
 1554 
     | 
    
         
            +
                  case MEASURE_GC_RUNS:
         
     | 
| 
      
 1555 
     | 
    
         
            +
                    get_measurement = measure_gc_runs;
         
     | 
| 
      
 1556 
     | 
    
         
            +
                    convert_measurement = convert_gc_runs;
         
     | 
| 
      
 1557 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1558 
     | 
    
         
            +
                  #endif
         
     | 
| 
      
 1559 
     | 
    
         
            +
             
     | 
| 
      
 1560 
     | 
    
         
            +
                  #if defined(MEASURE_GC_TIME)
         
     | 
| 
      
 1561 
     | 
    
         
            +
                  case MEASURE_GC_TIME:
         
     | 
| 
      
 1562 
     | 
    
         
            +
                    get_measurement = measure_gc_time;
         
     | 
| 
      
 1563 
     | 
    
         
            +
                    convert_measurement = convert_gc_time;
         
     | 
| 
      
 1564 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1565 
     | 
    
         
            +
                  #endif
         
     | 
| 
      
 1566 
     | 
    
         
            +
             
     | 
| 
      
 1567 
     | 
    
         
            +
                  default:
         
     | 
| 
      
 1568 
     | 
    
         
            +
                    rb_raise(rb_eArgError, "invalid mode: %ld", mode);
         
     | 
| 
      
 1569 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1570 
     | 
    
         
            +
                }
         
     | 
| 
      
 1571 
     | 
    
         
            +
                
         
     | 
| 
      
 1572 
     | 
    
         
            +
                measure_mode = mode;
         
     | 
| 
      
 1573 
     | 
    
         
            +
                return val;
         
     | 
| 
      
 1574 
     | 
    
         
            +
            }
         
     | 
| 
      
 1575 
     | 
    
         
            +
             
     | 
| 
      
 1576 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1577 
     | 
    
         
            +
               exclude_threads= -> void
         
     | 
| 
      
 1578 
     | 
    
         
            +
             
     | 
| 
      
 1579 
     | 
    
         
            +
               Specifies what threads ruby-prof should exclude from profiling */
         
     | 
| 
      
 1580 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1581 
     | 
    
         
            +
            prof_set_exclude_threads(VALUE self, VALUE threads)
         
     | 
| 
      
 1582 
     | 
    
         
            +
            {
         
     | 
| 
      
 1583 
     | 
    
         
            +
                int i;
         
     | 
| 
      
 1584 
     | 
    
         
            +
             
     | 
| 
      
 1585 
     | 
    
         
            +
                if (threads_tbl != NULL)
         
     | 
| 
      
 1586 
     | 
    
         
            +
                {
         
     | 
| 
      
 1587 
     | 
    
         
            +
                  rb_raise(rb_eRuntimeError, "can't set exclude_threads while profiling");
         
     | 
| 
      
 1588 
     | 
    
         
            +
                }
         
     | 
| 
      
 1589 
     | 
    
         
            +
             
     | 
| 
      
 1590 
     | 
    
         
            +
                /* Stay simple, first free the old hash table */
         
     | 
| 
      
 1591 
     | 
    
         
            +
                if (exclude_threads_tbl)
         
     | 
| 
      
 1592 
     | 
    
         
            +
                {
         
     | 
| 
      
 1593 
     | 
    
         
            +
                  st_free_table(exclude_threads_tbl);
         
     | 
| 
      
 1594 
     | 
    
         
            +
                  exclude_threads_tbl = NULL;
         
     | 
| 
      
 1595 
     | 
    
         
            +
                }
         
     | 
| 
      
 1596 
     | 
    
         
            +
             
     | 
| 
      
 1597 
     | 
    
         
            +
                /* Now create a new one if the user passed in any threads */
         
     | 
| 
      
 1598 
     | 
    
         
            +
                if (threads != Qnil)
         
     | 
| 
      
 1599 
     | 
    
         
            +
                {
         
     | 
| 
      
 1600 
     | 
    
         
            +
                  Check_Type(threads, T_ARRAY);
         
     | 
| 
      
 1601 
     | 
    
         
            +
                  exclude_threads_tbl = st_init_numtable();
         
     | 
| 
      
 1602 
     | 
    
         
            +
             
     | 
| 
      
 1603 
     | 
    
         
            +
                  for (i=0; i < RARRAY_LEN(threads); ++i) 
         
     | 
| 
      
 1604 
     | 
    
         
            +
                  {
         
     | 
| 
      
 1605 
     | 
    
         
            +
                    VALUE thread = rb_ary_entry(threads, i);
         
     | 
| 
      
 1606 
     | 
    
         
            +
                    st_insert(exclude_threads_tbl, (st_data_t) rb_obj_id(thread), 0);
         
     | 
| 
      
 1607 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1608 
     | 
    
         
            +
                }    
         
     | 
| 
      
 1609 
     | 
    
         
            +
                return threads;
         
     | 
| 
      
 1610 
     | 
    
         
            +
            }
         
     | 
| 
      
 1611 
     | 
    
         
            +
             
     | 
| 
      
 1612 
     | 
    
         
            +
             
     | 
| 
      
 1613 
     | 
    
         
            +
            /* =========  Profiling ============= */
         
     | 
| 
      
 1614 
     | 
    
         
            +
            void
         
     | 
| 
      
 1615 
     | 
    
         
            +
            prof_install_hook()
         
     | 
| 
      
 1616 
     | 
    
         
            +
            {
         
     | 
| 
      
 1617 
     | 
    
         
            +
            #ifdef RUBY_VM
         
     | 
| 
      
 1618 
     | 
    
         
            +
                rb_add_event_hook(prof_event_hook,
         
     | 
| 
      
 1619 
     | 
    
         
            +
                      RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
         
     | 
| 
      
 1620 
     | 
    
         
            +
                      RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN 
         
     | 
| 
      
 1621 
     | 
    
         
            +
                        | RUBY_EVENT_LINE, Qnil); // RUBY_EVENT_SWITCH
         
     | 
| 
      
 1622 
     | 
    
         
            +
            #else
         
     | 
| 
      
 1623 
     | 
    
         
            +
                rb_add_event_hook(prof_event_hook,
         
     | 
| 
      
 1624 
     | 
    
         
            +
                      RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
         
     | 
| 
      
 1625 
     | 
    
         
            +
                      RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN 
         
     | 
| 
      
 1626 
     | 
    
         
            +
                      | RUBY_EVENT_LINE);
         
     | 
| 
      
 1627 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1628 
     | 
    
         
            +
             
     | 
| 
      
 1629 
     | 
    
         
            +
            #if defined(TOGGLE_GC_STATS)
         
     | 
| 
      
 1630 
     | 
    
         
            +
                rb_gc_enable_stats();
         
     | 
| 
      
 1631 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1632 
     | 
    
         
            +
            }
         
     | 
| 
      
 1633 
     | 
    
         
            +
             
     | 
| 
      
 1634 
     | 
    
         
            +
            void
         
     | 
| 
      
 1635 
     | 
    
         
            +
            prof_remove_hook()
         
     | 
| 
      
 1636 
     | 
    
         
            +
            {
         
     | 
| 
      
 1637 
     | 
    
         
            +
            #if defined(TOGGLE_GC_STATS)
         
     | 
| 
      
 1638 
     | 
    
         
            +
                rb_gc_disable_stats();
         
     | 
| 
      
 1639 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1640 
     | 
    
         
            +
             
     | 
| 
      
 1641 
     | 
    
         
            +
                /* Now unregister from event   */
         
     | 
| 
      
 1642 
     | 
    
         
            +
                rb_remove_event_hook(prof_event_hook);
         
     | 
| 
      
 1643 
     | 
    
         
            +
            }
         
     | 
| 
      
 1644 
     | 
    
         
            +
             
     | 
| 
      
 1645 
     | 
    
         
            +
             
     | 
| 
      
 1646 
     | 
    
         
            +
             
     | 
| 
      
 1647 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1648 
     | 
    
         
            +
               running? -> boolean
         
     | 
| 
      
 1649 
     | 
    
         
            +
               
         
     | 
| 
      
 1650 
     | 
    
         
            +
               Returns whether a profile is currently running.*/
         
     | 
| 
      
 1651 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1652 
     | 
    
         
            +
            prof_running(VALUE self)
         
     | 
| 
      
 1653 
     | 
    
         
            +
            {
         
     | 
| 
      
 1654 
     | 
    
         
            +
                if (threads_tbl != NULL)
         
     | 
| 
      
 1655 
     | 
    
         
            +
                    return Qtrue;
         
     | 
| 
      
 1656 
     | 
    
         
            +
                else
         
     | 
| 
      
 1657 
     | 
    
         
            +
                    return Qfalse;
         
     | 
| 
      
 1658 
     | 
    
         
            +
            }
         
     | 
| 
      
 1659 
     | 
    
         
            +
             
     | 
| 
      
 1660 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1661 
     | 
    
         
            +
               start -> RubyProf
         
     | 
| 
      
 1662 
     | 
    
         
            +
               
         
     | 
| 
      
 1663 
     | 
    
         
            +
               Starts recording profile data.*/
         
     | 
| 
      
 1664 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1665 
     | 
    
         
            +
            prof_start(VALUE self)
         
     | 
| 
      
 1666 
     | 
    
         
            +
            {
         
     | 
| 
      
 1667 
     | 
    
         
            +
                if (call_tree_profile_on)
         
     | 
| 
      
 1668 
     | 
    
         
            +
                {
         
     | 
| 
      
 1669 
     | 
    
         
            +
                  call_tree_prof_start(self);
         
     | 
| 
      
 1670 
     | 
    
         
            +
                }
         
     | 
| 
      
 1671 
     | 
    
         
            +
                else 
         
     | 
| 
      
 1672 
     | 
    
         
            +
                {
         
     | 
| 
      
 1673 
     | 
    
         
            +
                  if (threads_tbl != NULL)
         
     | 
| 
      
 1674 
     | 
    
         
            +
                  {
         
     | 
| 
      
 1675 
     | 
    
         
            +
                      rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
         
     | 
| 
      
 1676 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1677 
     | 
    
         
            +
             
     | 
| 
      
 1678 
     | 
    
         
            +
                  /* Setup globals */
         
     | 
| 
      
 1679 
     | 
    
         
            +
                  last_thread_data = NULL;
         
     | 
| 
      
 1680 
     | 
    
         
            +
                  threads_tbl = threads_table_create();
         
     | 
| 
      
 1681 
     | 
    
         
            +
                }
         
     | 
| 
      
 1682 
     | 
    
         
            +
                prof_install_hook();              
         
     | 
| 
      
 1683 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 1684 
     | 
    
         
            +
            }    
         
     | 
| 
      
 1685 
     | 
    
         
            +
             
     | 
| 
      
 1686 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1687 
     | 
    
         
            +
               pause -> RubyProf
         
     | 
| 
      
 1688 
     | 
    
         
            +
             
     | 
| 
      
 1689 
     | 
    
         
            +
               Pauses collecting profile data. */
         
     | 
| 
      
 1690 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1691 
     | 
    
         
            +
            prof_pause(VALUE self)
         
     | 
| 
      
 1692 
     | 
    
         
            +
            {
         
     | 
| 
      
 1693 
     | 
    
         
            +
                if (threads_tbl == NULL)
         
     | 
| 
      
 1694 
     | 
    
         
            +
                {
         
     | 
| 
      
 1695 
     | 
    
         
            +
                    rb_raise(rb_eRuntimeError, "RubyProf is not running.");
         
     | 
| 
      
 1696 
     | 
    
         
            +
                }
         
     | 
| 
      
 1697 
     | 
    
         
            +
             
     | 
| 
      
 1698 
     | 
    
         
            +
                prof_remove_hook();
         
     | 
| 
      
 1699 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 1700 
     | 
    
         
            +
            }
         
     | 
| 
      
 1701 
     | 
    
         
            +
             
     | 
| 
      
 1702 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1703 
     | 
    
         
            +
               resume {block} -> RubyProf
         
     | 
| 
      
 1704 
     | 
    
         
            +
               
         
     | 
| 
      
 1705 
     | 
    
         
            +
               Resumes recording profile data.*/
         
     | 
| 
      
 1706 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1707 
     | 
    
         
            +
            prof_resume(VALUE self)
         
     | 
| 
      
 1708 
     | 
    
         
            +
            {
         
     | 
| 
      
 1709 
     | 
    
         
            +
                if (threads_tbl == NULL)
         
     | 
| 
      
 1710 
     | 
    
         
            +
                { 
         
     | 
| 
      
 1711 
     | 
    
         
            +
                    prof_start(self);
         
     | 
| 
      
 1712 
     | 
    
         
            +
                }
         
     | 
| 
      
 1713 
     | 
    
         
            +
                else
         
     | 
| 
      
 1714 
     | 
    
         
            +
                { 
         
     | 
| 
      
 1715 
     | 
    
         
            +
                    prof_install_hook();
         
     | 
| 
      
 1716 
     | 
    
         
            +
                }
         
     | 
| 
      
 1717 
     | 
    
         
            +
                
         
     | 
| 
      
 1718 
     | 
    
         
            +
                if (rb_block_given_p())
         
     | 
| 
      
 1719 
     | 
    
         
            +
                {
         
     | 
| 
      
 1720 
     | 
    
         
            +
                  rb_ensure(rb_yield, self, prof_pause, self);
         
     | 
| 
      
 1721 
     | 
    
         
            +
                }
         
     | 
| 
      
 1722 
     | 
    
         
            +
             
     | 
| 
      
 1723 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 1724 
     | 
    
         
            +
            }
         
     | 
| 
      
 1725 
     | 
    
         
            +
             
     | 
| 
      
 1726 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1727 
     | 
    
         
            +
               stop -> RubyProf::Result
         
     | 
| 
      
 1728 
     | 
    
         
            +
             
     | 
| 
      
 1729 
     | 
    
         
            +
               Stops collecting profile data and returns a RubyProf::Result object. */
         
     | 
| 
      
 1730 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1731 
     | 
    
         
            +
            prof_stop(VALUE self)
         
     | 
| 
      
 1732 
     | 
    
         
            +
            {
         
     | 
| 
      
 1733 
     | 
    
         
            +
                prof_remove_hook();
         
     | 
| 
      
 1734 
     | 
    
         
            +
             
     | 
| 
      
 1735 
     | 
    
         
            +
                if (call_tree_profile_on) 
         
     | 
| 
      
 1736 
     | 
    
         
            +
                {
         
     | 
| 
      
 1737 
     | 
    
         
            +
                  return call_tree_prof_stop(self);
         
     | 
| 
      
 1738 
     | 
    
         
            +
                }
         
     | 
| 
      
 1739 
     | 
    
         
            +
                else
         
     | 
| 
      
 1740 
     | 
    
         
            +
                {
         
     | 
| 
      
 1741 
     | 
    
         
            +
                  VALUE result = Qnil;
         
     | 
| 
      
 1742 
     | 
    
         
            +
             
     | 
| 
      
 1743 
     | 
    
         
            +
                  prof_pop_threads();
         
     | 
| 
      
 1744 
     | 
    
         
            +
             
     | 
| 
      
 1745 
     | 
    
         
            +
                  /* Create the result */
         
     | 
| 
      
 1746 
     | 
    
         
            +
                  result = prof_result_new();
         
     | 
| 
      
 1747 
     | 
    
         
            +
             
     | 
| 
      
 1748 
     | 
    
         
            +
                  /* Unset the last_thread_data (very important!) 
         
     | 
| 
      
 1749 
     | 
    
         
            +
                     and the threads table */
         
     | 
| 
      
 1750 
     | 
    
         
            +
                  last_thread_data = NULL;
         
     | 
| 
      
 1751 
     | 
    
         
            +
                  threads_table_free(threads_tbl);
         
     | 
| 
      
 1752 
     | 
    
         
            +
                  threads_tbl = NULL;
         
     | 
| 
      
 1753 
     | 
    
         
            +
             
     | 
| 
      
 1754 
     | 
    
         
            +
                  return result;
         
     | 
| 
      
 1755 
     | 
    
         
            +
                }
         
     | 
| 
      
 1756 
     | 
    
         
            +
            }
         
     | 
| 
      
 1757 
     | 
    
         
            +
             
     | 
| 
      
 1758 
     | 
    
         
            +
            /* call-seq:
         
     | 
| 
      
 1759 
     | 
    
         
            +
               profile {block} -> RubyProf::Result
         
     | 
| 
      
 1760 
     | 
    
         
            +
             
     | 
| 
      
 1761 
     | 
    
         
            +
            Profiles the specified block and returns a RubyProf::Result object. */
         
     | 
| 
      
 1762 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1763 
     | 
    
         
            +
            prof_profile(VALUE self)
         
     | 
| 
      
 1764 
     | 
    
         
            +
            {
         
     | 
| 
      
 1765 
     | 
    
         
            +
                int result;
         
     | 
| 
      
 1766 
     | 
    
         
            +
                
         
     | 
| 
      
 1767 
     | 
    
         
            +
                if (!rb_block_given_p())
         
     | 
| 
      
 1768 
     | 
    
         
            +
                {
         
     | 
| 
      
 1769 
     | 
    
         
            +
                    rb_raise(rb_eArgError, "A block must be provided to the profile method.");
         
     | 
| 
      
 1770 
     | 
    
         
            +
                }
         
     | 
| 
      
 1771 
     | 
    
         
            +
             
     | 
| 
      
 1772 
     | 
    
         
            +
                prof_start(self);
         
     | 
| 
      
 1773 
     | 
    
         
            +
                rb_protect(rb_yield, self, &result);
         
     | 
| 
      
 1774 
     | 
    
         
            +
                return prof_stop(self);
         
     | 
| 
      
 1775 
     | 
    
         
            +
            }
         
     | 
| 
      
 1776 
     | 
    
         
            +
             
     | 
| 
      
 1777 
     | 
    
         
            +
            /* Get arround annoying limitations in RDOC */
         
     | 
| 
      
 1778 
     | 
    
         
            +
             
     | 
| 
      
 1779 
     | 
    
         
            +
            /* Document-method: measure_process_time
         
     | 
| 
      
 1780 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1781 
     | 
    
         
            +
                 measure_process_time -> float
         
     | 
| 
      
 1782 
     | 
    
         
            +
             
     | 
| 
      
 1783 
     | 
    
         
            +
            Returns the process time.*/
         
     | 
| 
      
 1784 
     | 
    
         
            +
             
     | 
| 
      
 1785 
     | 
    
         
            +
            /* Document-method: measure_wall_time
         
     | 
| 
      
 1786 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1787 
     | 
    
         
            +
                 measure_wall_time -> float
         
     | 
| 
      
 1788 
     | 
    
         
            +
             
     | 
| 
      
 1789 
     | 
    
         
            +
            Returns the wall time.*/
         
     | 
| 
      
 1790 
     | 
    
         
            +
             
     | 
| 
      
 1791 
     | 
    
         
            +
            /* Document-method: measure_cpu_time
         
     | 
| 
      
 1792 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1793 
     | 
    
         
            +
                 measure_cpu_time -> float
         
     | 
| 
      
 1794 
     | 
    
         
            +
             
     | 
| 
      
 1795 
     | 
    
         
            +
            Returns the cpu time.*/
         
     | 
| 
      
 1796 
     | 
    
         
            +
             
     | 
| 
      
 1797 
     | 
    
         
            +
            /* Document-method: get_cpu_frequency
         
     | 
| 
      
 1798 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1799 
     | 
    
         
            +
                 cpu_frequency -> int
         
     | 
| 
      
 1800 
     | 
    
         
            +
             
     | 
| 
      
 1801 
     | 
    
         
            +
            Returns the cpu's frequency.  This value is needed when 
         
     | 
| 
      
 1802 
     | 
    
         
            +
            RubyProf::measure_mode is set to CPU_TIME. */
         
     | 
| 
      
 1803 
     | 
    
         
            +
             
     | 
| 
      
 1804 
     | 
    
         
            +
            /* Document-method: cpu_frequency
         
     | 
| 
      
 1805 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1806 
     | 
    
         
            +
                 cpu_frequency -> int
         
     | 
| 
      
 1807 
     | 
    
         
            +
             
     | 
| 
      
 1808 
     | 
    
         
            +
            Returns the cpu's frequency.  This value is needed when 
         
     | 
| 
      
 1809 
     | 
    
         
            +
            RubyProf::measure_mode is set to CPU_TIME. */
         
     | 
| 
      
 1810 
     | 
    
         
            +
             
     | 
| 
      
 1811 
     | 
    
         
            +
            /* Document-method: cpu_frequency=
         
     | 
| 
      
 1812 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1813 
     | 
    
         
            +
                 cpu_frequency = frequency
         
     | 
| 
      
 1814 
     | 
    
         
            +
             
     | 
| 
      
 1815 
     | 
    
         
            +
            Sets the cpu's frequency.  This value is needed when 
         
     | 
| 
      
 1816 
     | 
    
         
            +
            RubyProf::measure_mode is set to CPU_TIME. */
         
     | 
| 
      
 1817 
     | 
    
         
            +
             
     | 
| 
      
 1818 
     | 
    
         
            +
            /* Document-method: measure_allocations
         
     | 
| 
      
 1819 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1820 
     | 
    
         
            +
                 measure_allocations -> int
         
     | 
| 
      
 1821 
     | 
    
         
            +
             
     | 
| 
      
 1822 
     | 
    
         
            +
            Returns the total number of object allocations since Ruby started.*/
         
     | 
| 
      
 1823 
     | 
    
         
            +
             
     | 
| 
      
 1824 
     | 
    
         
            +
            /* Document-method: measure_memory
         
     | 
| 
      
 1825 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1826 
     | 
    
         
            +
                 measure_memory -> int
         
     | 
| 
      
 1827 
     | 
    
         
            +
             
     | 
| 
      
 1828 
     | 
    
         
            +
            Returns total allocated memory in bytes.*/
         
     | 
| 
      
 1829 
     | 
    
         
            +
             
     | 
| 
      
 1830 
     | 
    
         
            +
            /* Document-method: measure_gc_runs
         
     | 
| 
      
 1831 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1832 
     | 
    
         
            +
                 gc_runs -> Integer
         
     | 
| 
      
 1833 
     | 
    
         
            +
             
     | 
| 
      
 1834 
     | 
    
         
            +
            Returns the total number of garbage collections.*/
         
     | 
| 
      
 1835 
     | 
    
         
            +
             
     | 
| 
      
 1836 
     | 
    
         
            +
            /* Document-method: measure_gc_time
         
     | 
| 
      
 1837 
     | 
    
         
            +
               call-seq:
         
     | 
| 
      
 1838 
     | 
    
         
            +
                 gc_time -> Integer
         
     | 
| 
      
 1839 
     | 
    
         
            +
             
     | 
| 
      
 1840 
     | 
    
         
            +
            Returns the time spent doing garbage collections in microseconds.*/
         
     | 
| 
      
 1841 
     | 
    
         
            +
             
     | 
| 
      
 1842 
     | 
    
         
            +
             
     | 
| 
      
 1843 
     | 
    
         
            +
            #if defined(_WIN32)
         
     | 
| 
      
 1844 
     | 
    
         
            +
            __declspec(dllexport) 
         
     | 
| 
      
 1845 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 1846 
     | 
    
         
            +
            void
         
     | 
| 
      
 1847 
     | 
    
         
            +
             
     | 
| 
      
 1848 
     | 
    
         
            +
            Init_ruby_prof()
         
     | 
| 
      
 1849 
     | 
    
         
            +
            {
         
     | 
| 
      
 1850 
     | 
    
         
            +
                mProf = rb_define_module("RubyProf");
         
     | 
| 
      
 1851 
     | 
    
         
            +
                rb_define_const(mProf, "VERSION", rb_str_new2(RUBY_PROF_VERSION));
         
     | 
| 
      
 1852 
     | 
    
         
            +
                rb_define_module_function(mProf, "start", prof_start, 0);
         
     | 
| 
      
 1853 
     | 
    
         
            +
                rb_define_module_function(mProf, "stop", prof_stop, 0);
         
     | 
| 
      
 1854 
     | 
    
         
            +
                rb_define_module_function(mProf, "resume", prof_resume, 0);
         
     | 
| 
      
 1855 
     | 
    
         
            +
                rb_define_module_function(mProf, "pause", prof_pause, 0);
         
     | 
| 
      
 1856 
     | 
    
         
            +
                rb_define_module_function(mProf, "running?", prof_running, 0);
         
     | 
| 
      
 1857 
     | 
    
         
            +
                rb_define_module_function(mProf, "profile", prof_profile, 0);
         
     | 
| 
      
 1858 
     | 
    
         
            +
                
         
     | 
| 
      
 1859 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "exclude_threads=", prof_set_exclude_threads, 1);
         
     | 
| 
      
 1860 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_mode", prof_get_measure_mode, 0);
         
     | 
| 
      
 1861 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_mode=", prof_set_measure_mode, 1);
         
     | 
| 
      
 1862 
     | 
    
         
            +
             
     | 
| 
      
 1863 
     | 
    
         
            +
                // CALL_TREE
         
     | 
| 
      
 1864 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "call_tree_profile_on", prof_get_call_tree_profile_on, 0);
         
     | 
| 
      
 1865 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "call_tree_profile_on=", prof_set_call_tree_profile_on, 1);
         
     | 
| 
      
 1866 
     | 
    
         
            +
             
     | 
| 
      
 1867 
     | 
    
         
            +
             
     | 
| 
      
 1868 
     | 
    
         
            +
                rb_define_const(mProf, "CLOCKS_PER_SEC", INT2NUM(CLOCKS_PER_SEC));
         
     | 
| 
      
 1869 
     | 
    
         
            +
                rb_define_const(mProf, "PROCESS_TIME", INT2NUM(MEASURE_PROCESS_TIME));
         
     | 
| 
      
 1870 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_process_time", prof_measure_process_time, 0); /* in measure_process_time.h */
         
     | 
| 
      
 1871 
     | 
    
         
            +
                rb_define_const(mProf, "WALL_TIME", INT2NUM(MEASURE_WALL_TIME));
         
     | 
| 
      
 1872 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_wall_time", prof_measure_wall_time, 0); /* in measure_wall_time.h */
         
     | 
| 
      
 1873 
     | 
    
         
            +
             
     | 
| 
      
 1874 
     | 
    
         
            +
                #ifndef MEASURE_CPU_TIME
         
     | 
| 
      
 1875 
     | 
    
         
            +
                rb_define_const(mProf, "CPU_TIME", Qnil);
         
     | 
| 
      
 1876 
     | 
    
         
            +
                #else
         
     | 
| 
      
 1877 
     | 
    
         
            +
                rb_define_const(mProf, "CPU_TIME", INT2NUM(MEASURE_CPU_TIME));
         
     | 
| 
      
 1878 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_cpu_time", prof_measure_cpu_time, 0); /* in measure_cpu_time.h */
         
     | 
| 
      
 1879 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "cpu_frequency", prof_get_cpu_frequency, 0); /* in measure_cpu_time.h */
         
     | 
| 
      
 1880 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "cpu_frequency=", prof_set_cpu_frequency, 1); /* in measure_cpu_time.h */
         
     | 
| 
      
 1881 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1882 
     | 
    
         
            +
                    
         
     | 
| 
      
 1883 
     | 
    
         
            +
                #ifndef MEASURE_ALLOCATIONS
         
     | 
| 
      
 1884 
     | 
    
         
            +
                rb_define_const(mProf, "ALLOCATIONS", Qnil);
         
     | 
| 
      
 1885 
     | 
    
         
            +
                #else
         
     | 
| 
      
 1886 
     | 
    
         
            +
                rb_define_const(mProf, "ALLOCATIONS", INT2NUM(MEASURE_ALLOCATIONS));
         
     | 
| 
      
 1887 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_allocations", prof_measure_allocations, 0); /* in measure_allocations.h */
         
     | 
| 
      
 1888 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1889 
     | 
    
         
            +
                
         
     | 
| 
      
 1890 
     | 
    
         
            +
                #ifndef MEASURE_MEMORY
         
     | 
| 
      
 1891 
     | 
    
         
            +
                rb_define_const(mProf, "MEMORY", Qnil);
         
     | 
| 
      
 1892 
     | 
    
         
            +
                #else
         
     | 
| 
      
 1893 
     | 
    
         
            +
                rb_define_const(mProf, "MEMORY", INT2NUM(MEASURE_MEMORY));
         
     | 
| 
      
 1894 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_memory", prof_measure_memory, 0); /* in measure_memory.h */
         
     | 
| 
      
 1895 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1896 
     | 
    
         
            +
             
     | 
| 
      
 1897 
     | 
    
         
            +
                #ifndef MEASURE_GC_RUNS
         
     | 
| 
      
 1898 
     | 
    
         
            +
                rb_define_const(mProf, "GC_RUNS", Qnil);
         
     | 
| 
      
 1899 
     | 
    
         
            +
                #else
         
     | 
| 
      
 1900 
     | 
    
         
            +
                rb_define_const(mProf, "GC_RUNS", INT2NUM(MEASURE_GC_RUNS));
         
     | 
| 
      
 1901 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_gc_runs", prof_measure_gc_runs, 0); /* in measure_gc_runs.h */
         
     | 
| 
      
 1902 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1903 
     | 
    
         
            +
             
     | 
| 
      
 1904 
     | 
    
         
            +
                #ifndef MEASURE_GC_TIME
         
     | 
| 
      
 1905 
     | 
    
         
            +
                rb_define_const(mProf, "GC_TIME", Qnil);
         
     | 
| 
      
 1906 
     | 
    
         
            +
                #else
         
     | 
| 
      
 1907 
     | 
    
         
            +
                rb_define_const(mProf, "GC_TIME", INT2NUM(MEASURE_GC_TIME));
         
     | 
| 
      
 1908 
     | 
    
         
            +
                rb_define_singleton_method(mProf, "measure_gc_time", prof_measure_gc_time, 0); /* in measure_gc_time.h */
         
     | 
| 
      
 1909 
     | 
    
         
            +
                #endif
         
     | 
| 
      
 1910 
     | 
    
         
            +
             
     | 
| 
      
 1911 
     | 
    
         
            +
                cResult = rb_define_class_under(mProf, "Result", rb_cObject);
         
     | 
| 
      
 1912 
     | 
    
         
            +
                rb_undef_method(CLASS_OF(cMethodInfo), "new");
         
     | 
| 
      
 1913 
     | 
    
         
            +
                rb_define_method(cResult, "threads", prof_result_threads, 0);
         
     | 
| 
      
 1914 
     | 
    
         
            +
             
     | 
| 
      
 1915 
     | 
    
         
            +
                /* MethodInfo */
         
     | 
| 
      
 1916 
     | 
    
         
            +
                cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
         
     | 
| 
      
 1917 
     | 
    
         
            +
                rb_undef_method(CLASS_OF(cMethodInfo), "new");
         
     | 
| 
      
 1918 
     | 
    
         
            +
                
         
     | 
| 
      
 1919 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
         
     | 
| 
      
 1920 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
         
     | 
| 
      
 1921 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
         
     | 
| 
      
 1922 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
         
     | 
| 
      
 1923 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
         
     | 
| 
      
 1924 
     | 
    
         
            +
                
         
     | 
| 
      
 1925 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "source_file", prof_method_source_file,0);
         
     | 
| 
      
 1926 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "line", prof_method_line, 0);
         
     | 
| 
      
 1927 
     | 
    
         
            +
             
     | 
| 
      
 1928 
     | 
    
         
            +
                rb_define_method(cMethodInfo, "call_infos", prof_method_call_infos, 0);
         
     | 
| 
      
 1929 
     | 
    
         
            +
             
     | 
| 
      
 1930 
     | 
    
         
            +
                /* CallInfo */
         
     | 
| 
      
 1931 
     | 
    
         
            +
                cCallInfo = rb_define_class_under(mProf, "CallInfo", rb_cObject);
         
     | 
| 
      
 1932 
     | 
    
         
            +
                rb_undef_method(CLASS_OF(cCallInfo), "new");
         
     | 
| 
      
 1933 
     | 
    
         
            +
                rb_define_method(cCallInfo, "parent", prof_call_info_parent, 0);
         
     | 
| 
      
 1934 
     | 
    
         
            +
                rb_define_method(cCallInfo, "children", prof_call_info_children, 0);
         
     | 
| 
      
 1935 
     | 
    
         
            +
                rb_define_method(cCallInfo, "target", prof_call_info_target, 0);
         
     | 
| 
      
 1936 
     | 
    
         
            +
                rb_define_method(cCallInfo, "called", prof_call_info_called, 0);
         
     | 
| 
      
 1937 
     | 
    
         
            +
                rb_define_method(cCallInfo, "total_time", prof_call_info_total_time, 0);
         
     | 
| 
      
 1938 
     | 
    
         
            +
                rb_define_method(cCallInfo, "self_time", prof_call_info_self_time, 0);
         
     | 
| 
      
 1939 
     | 
    
         
            +
                rb_define_method(cCallInfo, "wait_time", prof_call_info_wait_time, 0);
         
     | 
| 
      
 1940 
     | 
    
         
            +
                rb_define_method(cCallInfo, "line", prof_call_info_line, 0);
         
     | 
| 
      
 1941 
     | 
    
         
            +
             
     | 
| 
      
 1942 
     | 
    
         
            +
                init_call_tree();
         
     | 
| 
      
 1943 
     | 
    
         
            +
            }
         
     |