ruby_memprofiler_pprof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +7 -0
  2. data/ext/ruby_memprofiler_pprof/backtrace.c +429 -0
  3. data/ext/ruby_memprofiler_pprof/collector.c +1055 -0
  4. data/ext/ruby_memprofiler_pprof/compat.c +182 -0
  5. data/ext/ruby_memprofiler_pprof/extconf.rb +72 -0
  6. data/ext/ruby_memprofiler_pprof/pprof.upb.c +170 -0
  7. data/ext/ruby_memprofiler_pprof/pprof.upb.h +848 -0
  8. data/ext/ruby_memprofiler_pprof/pprof_out.c +285 -0
  9. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +11 -0
  10. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +301 -0
  11. data/ext/ruby_memprofiler_pprof/strtab.c +391 -0
  12. data/ext/ruby_memprofiler_pprof/vendor/upb/BUILD +719 -0
  13. data/ext/ruby_memprofiler_pprof/vendor/upb/CONTRIBUTING.md +37 -0
  14. data/ext/ruby_memprofiler_pprof/vendor/upb/DESIGN.md +201 -0
  15. data/ext/ruby_memprofiler_pprof/vendor/upb/LICENSE +26 -0
  16. data/ext/ruby_memprofiler_pprof/vendor/upb/README.md +78 -0
  17. data/ext/ruby_memprofiler_pprof/vendor/upb/WORKSPACE +58 -0
  18. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/BUILD +53 -0
  19. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/amalgamate.py +129 -0
  20. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/build_defs.bzl +160 -0
  21. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/lua.BUILD +127 -0
  22. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/protobuf.patch +54 -0
  23. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/py_proto_library.bzl +137 -0
  24. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/python_downloads.bzl +84 -0
  25. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/system_python.bzl +101 -0
  26. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/upb_proto_library.bzl +388 -0
  27. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/workspace_deps.bzl +89 -0
  28. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD +252 -0
  29. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD.googleapis +54 -0
  30. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/benchmark.cc +333 -0
  31. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/build_defs.bzl +88 -0
  32. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/compare.py +118 -0
  33. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor.proto +888 -0
  34. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor_sv.proto +890 -0
  35. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/empty.proto +6 -0
  36. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +64 -0
  37. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_synthetic_protos.py +118 -0
  38. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_upb_binary_c.py +65 -0
  39. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/BUILD.bazel +102 -0
  40. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/README.md +23 -0
  41. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/build_defs.bzl +73 -0
  42. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/make_cmakelists.py +340 -0
  43. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test.py +57 -0
  44. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test_lib.py +186 -0
  45. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/render.py +43 -0
  46. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/style-guide.md +65 -0
  47. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/vs-cpp-protos.md +255 -0
  48. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/wrapping-upb.md +444 -0
  49. data/ext/ruby_memprofiler_pprof/vendor/upb/python/BUILD +216 -0
  50. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.c +394 -0
  51. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.h +63 -0
  52. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.c +1694 -0
  53. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.h +80 -0
  54. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.c +704 -0
  55. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.h +114 -0
  56. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.c +650 -0
  57. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.h +48 -0
  58. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/BUILD.bazel +193 -0
  59. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/dist.bzl +190 -0
  60. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.c +247 -0
  61. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.h +39 -0
  62. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.c +522 -0
  63. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.h +66 -0
  64. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.c +1909 -0
  65. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.h +101 -0
  66. data/ext/ruby_memprofiler_pprof/vendor/upb/python/minimal_test.py +183 -0
  67. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/BUILD +70 -0
  68. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/README.md +11 -0
  69. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +30 -0
  70. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +45 -0
  71. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +46 -0
  72. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +30 -0
  73. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +30 -0
  74. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +30 -0
  75. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +37 -0
  76. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +52 -0
  77. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +32 -0
  78. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +36 -0
  79. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +45 -0
  80. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +30 -0
  81. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +30 -0
  82. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +30 -0
  83. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +30 -0
  84. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +30 -0
  85. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +36 -0
  86. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +30 -0
  87. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.c +350 -0
  88. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.h +230 -0
  89. data/ext/ruby_memprofiler_pprof/vendor/upb/python/py_extension.bzl +55 -0
  90. data/ext/ruby_memprofiler_pprof/vendor/upb/python/python_api.h +61 -0
  91. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.c +828 -0
  92. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.h +69 -0
  93. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.c +404 -0
  94. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.h +39 -0
  95. data/ext/ruby_memprofiler_pprof/vendor/upb/python/version_script.lds +6 -0
  96. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/LICENSE +32 -0
  97. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/README.google +9 -0
  98. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/console.lua +156 -0
  99. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/lunit.lua +725 -0
  100. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/BUILD +19 -0
  101. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/LICENSE +21 -0
  102. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/naive.c +92 -0
  103. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-neon.c +157 -0
  104. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-sse.c +170 -0
  105. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/utf8_range.h +9 -0
  106. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/BUILD.bazel +129 -0
  107. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/README.md +8 -0
  108. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/def.c +939 -0
  109. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +138 -0
  110. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/main.c +83 -0
  111. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/msg.c +1118 -0
  112. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test.proto +69 -0
  113. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test_upb.lua +846 -0
  114. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.c +258 -0
  115. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.h +132 -0
  116. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.lua +58 -0
  117. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upbc.cc +134 -0
  118. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.c +192 -0
  119. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.h +174 -0
  120. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb.c +346 -0
  121. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb_failures.txt +1 -0
  122. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.c +1221 -0
  123. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.h +94 -0
  124. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.c +1055 -0
  125. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.h +153 -0
  126. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_internal.h +211 -0
  127. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.c +3262 -0
  128. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.h +414 -0
  129. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.hpp +438 -0
  130. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/empty.proto +1 -0
  131. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.c +604 -0
  132. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.h +71 -0
  133. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/BUILD +13 -0
  134. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +43 -0
  135. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.c +1509 -0
  136. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.h +47 -0
  137. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.c +776 -0
  138. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.h +62 -0
  139. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.c +1147 -0
  140. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.h +189 -0
  141. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.hpp +112 -0
  142. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.c +363 -0
  143. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.h +263 -0
  144. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_internal.h +59 -0
  145. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_test.cc +425 -0
  146. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_test.cc +230 -0
  147. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.c +428 -0
  148. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.h +114 -0
  149. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_internal.h +836 -0
  150. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.cc +491 -0
  151. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.proto +195 -0
  152. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_def.inc +261 -0
  153. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_undef.inc +62 -0
  154. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.c +323 -0
  155. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.h +109 -0
  156. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.hpp +37 -0
  157. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table.c +926 -0
  158. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table_internal.h +385 -0
  159. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test.proto +74 -0
  160. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.cc +186 -0
  161. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.proto +12 -0
  162. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_generated_code.cc +977 -0
  163. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_table.cc +580 -0
  164. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.c +472 -0
  165. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.h +64 -0
  166. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.c +362 -0
  167. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.h +378 -0
  168. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.hpp +115 -0
  169. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb_internal.h +68 -0
  170. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/BUILD +121 -0
  171. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/README.md +7 -0
  172. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.c +300 -0
  173. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.h +66 -0
  174. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare_test.cc +236 -0
  175. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.c +572 -0
  176. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.h +62 -0
  177. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_public_import_test.proto +32 -0
  178. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +36 -0
  179. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.cc +143 -0
  180. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.proto +119 -0
  181. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +28 -0
  182. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +28 -0
  183. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.c +311 -0
  184. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.h +94 -0
  185. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.cc +202 -0
  186. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.proto +48 -0
  187. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/BUILD +78 -0
  188. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.cc +77 -0
  189. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.h +112 -0
  190. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upb.cc +1997 -0
  191. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upbdefs.cc +193 -0
  192. data/lib/ruby_memprofiler_pprof/atfork.rb +77 -0
  193. data/lib/ruby_memprofiler_pprof/block_flusher.rb +61 -0
  194. data/lib/ruby_memprofiler_pprof/file_flusher.rb +45 -0
  195. data/lib/ruby_memprofiler_pprof/profile_app.rb +30 -0
  196. data/lib/ruby_memprofiler_pprof/profile_data.rb +18 -0
  197. data/lib/ruby_memprofiler_pprof/version.rb +5 -0
  198. data/lib/ruby_memprofiler_pprof.rb +8 -0
  199. data/libexec/ruby_memprofiler_pprof_profile +16 -0
  200. metadata +257 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2436cc3e0be185caaf180f2338b2c2b101cef94264065e5a402f8cc3297086ac
4
+ data.tar.gz: 9beaf364fe5ec7ebb0933e3176d21bab366a603f7db2335c31cb61a6808f322d
5
+ SHA512:
6
+ metadata.gz: e680e47549b85ca52746c7f2f4d1fa984f314f3a62cb78ebac391f7cd8291c6d13603cafac35dbba3e34ff65ca65ba53e5b20ce5cf9f424c4c945b2a3c06e0bf
7
+ data.tar.gz: add142be691cb74dcb6ca86f051471e75bfbee5868d0f44e3adf11aa819c74c3b608448cf176451f9725d3038927185dab70a3406b4199db579c78cc6d41cf82
@@ -0,0 +1,429 @@
1
+ // External ruby headers
2
+ #include <ruby.h>
3
+ #include <ruby/debug.h>
4
+ // Also include _INTERNAL_ ruby headers, from the debase-ruby_core_source gem.
5
+ // This will let us reach into the guts of the Ruby interpreter in a very, VERY
6
+ // API-unstable way.
7
+ #include <vm_core.h>
8
+ #include <iseq.h>
9
+
10
+ #include "ruby_memprofiler_pprof.h"
11
+
12
+ // We need access to the rb_vm_frame_method_entry method from vm_insnhelper.c; this function
13
+ // gives us the method information for C functions in Ruby backtraces.
14
+ // We have a prototype in vm_core.h, and the implementation in vm_insnhelper.c is "extern"
15
+ // (i.e. it is not "static").
16
+ //
17
+ // That would _normally_ mean we can simply just call it, BUT - Ruby is compiled by default
18
+ // with -fvisibility=hidden. That makes the function callable by other C files in the Ruby
19
+ // source tree, but it's NOT callable from code in other .so files (like our C extension);
20
+ // the linker marks the symbol as STV_HIDDEN in the .so file when it's linked. So, if we
21
+ // simply try to call it, when requiring our extension, the dynamic loader will complain
22
+ // that it can't resolve the symbol rb_vm_frame_method_entry.
23
+ //
24
+ // (In case you were wondering, other Ruby functions that are supposed to be called from
25
+ // C extensions are marked with "#pragma GCC visibility push(default)", which marks the
26
+ // function with "default visibility" and thus overrides -fvisibility=hidden and allows
27
+ // the function to be called).
28
+ //
29
+ // To work around this, I copied the definition of rb_vm_frame_method_entry (and
30
+ // check_method_entry, which it calls) into this file. I checked and the implementation
31
+ // is pretty much identical from Ruby 2.6.0 -> 3.1.0 so this _should_ be OK. Note that
32
+ // we also mark _our_ copy of this function as __attribute__(( visibility("hidden") ))
33
+ // so that we don't export it either.
34
+
35
+ static rb_callable_method_entry_t *
36
+ check_method_entry(VALUE obj, int can_be_svar)
37
+ {
38
+ if (obj == Qfalse) return NULL;
39
+
40
+ #if VM_CHECK_MODE > 0
41
+ if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
42
+ #endif
43
+
44
+ switch (imemo_type(obj)) {
45
+ case imemo_ment:
46
+ return (rb_callable_method_entry_t *)obj;
47
+ case imemo_cref:
48
+ return NULL;
49
+ case imemo_svar:
50
+ if (can_be_svar) {
51
+ return check_method_entry(((struct vm_svar *)obj)->cref_or_me, 0);
52
+ }
53
+ // falls through
54
+ default:
55
+ #if VM_CHECK_MODE > 0
56
+ rb_bug("check_method_entry: svar should not be there:");
57
+ #endif
58
+ return NULL;
59
+ }
60
+ }
61
+
62
+ __attribute__(( visibility("hidden") ))
63
+ const rb_callable_method_entry_t *
64
+ rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
65
+ {
66
+ const VALUE *ep = cfp->ep;
67
+ rb_callable_method_entry_t *me;
68
+
69
+ while (!VM_ENV_LOCAL_P(ep)) {
70
+ if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], 0)) != NULL) return me;
71
+ ep = VM_ENV_PREV_EP(ep);
72
+ }
73
+ return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], 1);
74
+ }
75
+
76
+ // Allocates, initializes and returns a new location table. A location table keeps track of a mapping
77
+ // of (compact!) location IDs to functions/line numbers. This keeps things in a convenient form for
78
+ // later turning to pprof, but also makes sure that we don't store the same char *'s for function/file
79
+ // names over and over again.
80
+ // Requires a reference to a string interning table, which must be valid for the lifetime of this
81
+ // loctab object.
82
+ struct mpp_rb_loctab *mpp_rb_loctab_new(struct mpp_strtab *strtab) {
83
+ struct mpp_rb_loctab *loctab = mpp_xmalloc(sizeof(struct mpp_rb_loctab));
84
+ loctab->strtab = strtab;
85
+ loctab->functions = st_init_numtable();
86
+ loctab->locations = st_init_numtable();
87
+ loctab->function_count = 0;
88
+ loctab->location_count = 0;
89
+ return loctab;
90
+ }
91
+
92
+ // Destroys the loctab, including its own memory.
93
+ void mpp_rb_loctab_destroy(struct mpp_rb_loctab *loctab) {
94
+ st_free_table(loctab->functions);
95
+ st_free_table(loctab->locations);
96
+ mpp_free(loctab);
97
+ }
98
+
99
+ struct fnloc_st_update_args {
100
+ struct mpp_rb_loctab *loctab;
101
+ uint64_t location_id;
102
+ uint64_t function_id;
103
+ struct mpp_rb_loctab_location *location;
104
+ struct mpp_rb_loctab_function *function;
105
+ VALUE fn_name_value;
106
+ VALUE file_name_value;
107
+ uint64_t location_line_number;
108
+ int64_t function_line_number;
109
+ };
110
+
111
+
112
+ static int function_st_update(st_data_t *key, st_data_t *value, st_data_t ctx, int exists) {
113
+ struct fnloc_st_update_args *args = (struct fnloc_st_update_args *)ctx;
114
+
115
+ if (exists) {
116
+ // Function already exists; put it in our outargs
117
+ args->function = (struct mpp_rb_loctab_function *)*value;
118
+ } else {
119
+ // Function doesn't exist; build it.
120
+ args->function = mpp_xmalloc(sizeof(struct mpp_rb_loctab_function));
121
+ *value = (st_data_t)args->function;
122
+ args->function->refcount = 0; // Will be incrmeented in backtrace_capture
123
+ args->function->id = args->function_id;
124
+ args->loctab->function_count++;
125
+
126
+ mpp_strtab_intern_rbstr(
127
+ args->loctab->strtab, args->fn_name_value,
128
+ &args->function->function_name, &args->function->function_name_len
129
+ );
130
+
131
+ if (RTEST(args->file_name_value)) {
132
+ mpp_strtab_intern_rbstr(
133
+ args->loctab->strtab, args->file_name_value,
134
+ &args->function->file_name, &args->function->file_name_len
135
+ );
136
+ } else {
137
+ mpp_strtab_intern_cstr(
138
+ args->loctab->strtab, "(unknown filename)",
139
+ &args->function->file_name, &args->function->file_name_len
140
+ );
141
+ }
142
+ args->function->line_number = args->function_line_number;
143
+ }
144
+
145
+ return ST_CONTINUE;
146
+ }
147
+
148
+ static int location_st_update(st_data_t *key, st_data_t *value, st_data_t ctx, int exists) {
149
+ struct fnloc_st_update_args *args = (struct fnloc_st_update_args *)ctx;
150
+
151
+ if (exists) {
152
+ // Location already exists - put it in our outargs.
153
+ args->location = (struct mpp_rb_loctab_location *)*value;
154
+ args->function = args->location->function;
155
+ } else {
156
+ // Location does not already exist. Make a new one.
157
+ args->location = mpp_xmalloc(sizeof(struct mpp_rb_loctab_location));
158
+ *value = (st_data_t)args->location;
159
+ args->location->refcount = 0; // will be incremented in backtrace_capture
160
+ args->location->id = args->location_id;
161
+ args->loctab->location_count++;
162
+
163
+ // Need to find a _function_ for it too.
164
+ st_update(args->loctab->functions, args->function_id, function_st_update, (st_data_t)args);
165
+ args->location->function = args->function;
166
+ args->location->line_number = args->location_line_number;
167
+ }
168
+
169
+ return ST_CONTINUE;
170
+ }
171
+
172
+ static int function_st_deref(st_data_t *key, st_data_t *value, st_data_t ctx, int exists) {
173
+ struct mpp_rb_loctab *loctab = (struct mpp_rb_loctab *)ctx;
174
+
175
+ MPP_ASSERT_MSG(exists, "attempted to decrement refcount on non-existing function");
176
+ struct mpp_rb_loctab_function *fn = (struct mpp_rb_loctab_function *)*value;
177
+ MPP_ASSERT_MSG(fn->refcount > 0, "attempted to decrement zero refcount on function");
178
+ fn->refcount--;
179
+ if (fn->refcount == 0) {
180
+ // Unref its string table entries.
181
+ mpp_strtab_release(loctab->strtab, fn->function_name, fn->function_name_len);
182
+ mpp_strtab_release(loctab->strtab, fn->file_name, fn->file_name_len);
183
+ mpp_free(fn);
184
+ loctab->function_count--;
185
+ return ST_DELETE;
186
+ }
187
+ return ST_CONTINUE;
188
+ }
189
+
190
+ static int location_st_deref(st_data_t *key, st_data_t *value, st_data_t ctx, int exists) {
191
+ struct mpp_rb_loctab *loctab = (struct mpp_rb_loctab *)ctx;
192
+
193
+ MPP_ASSERT_MSG(exists, "attempted to decrement refcount on non-existing location");
194
+ struct mpp_rb_loctab_location *loc = (struct mpp_rb_loctab_location *)*value;
195
+ MPP_ASSERT_MSG(loc->refcount > 0, "attempted to decrement zero refcount on location");
196
+ loc->refcount--;
197
+ if (loc->refcount == 0) {
198
+ // Deref its function too.
199
+ st_update(loctab->functions, loc->function->id, function_st_deref, (st_data_t)loctab);
200
+ mpp_free(loc);
201
+ loctab->location_count--;
202
+ return ST_DELETE;
203
+ }
204
+ return ST_CONTINUE;
205
+ }
206
+
207
+ // Captures a backtrace!
208
+ //
209
+ // This method uses internal Ruby headers to implement a rough copy of what backtrace_each in vm_backtrace.c
210
+ // does. This is _TREMENDOUSLY_ faster than actually calling rb_make_backtrace, because that creates Ruby
211
+ // VALUE objects to hold its result. Doing so from a newobj tracepoint is legal, AFAICT, but really slow
212
+ // (from my profiling of the profiler, doing this causes the garbage collector to run, _a lot_, in the
213
+ // middle of creating the original object).
214
+ //
215
+ // By poking directly at the VM internal structures, we can stuff the result into C structures and not
216
+ // allocate any ruby VALUEs avoiding this issue. It's a _LOT_ faster - it takes the overhead from ~50%
217
+ // (with 1% of allocations ampled), to < 1%. So it's definitely worthwhile despite how disgusting it is.
218
+ //
219
+ // Also note: This captures backtraces most recent call LAST, which is the opposite order to how the pprof
220
+ // protobuf wants them, so they have to be reversed later. It's not so convenient to just capture it in
221
+ // the correct order because we may have to skip some frames; thus if we filled in the frame array backwards,
222
+ // we might not actually wind up filling frames[0].
223
+ //
224
+ // This method allocates a struct mpp_rb_backtrace and saves it to *bt_out. The reason for this awkward
225
+ // calling convention (as opposed to just returning it) is so that the caller can detect if we got longjmp'd
226
+ // out of here by some of the Ruby calls below, and appropriately destroy *bt_out via a call to destroy.
227
+ void mpp_rb_backtrace_capture(struct mpp_rb_loctab *loctab, struct mpp_rb_backtrace **bt_out) {
228
+ const rb_control_frame_t *last_cfp = GET_EC()->cfp;
229
+ const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(GET_EC());
230
+
231
+ // Allegedly, according to vm_backtrace.c, we need to skip the first two control frames because they
232
+ // are "dummy frames", whatever that means.
233
+ start_cfp = RUBY_VM_NEXT_CONTROL_FRAME(start_cfp);
234
+ start_cfp = RUBY_VM_NEXT_CONTROL_FRAME(start_cfp);
235
+
236
+ // Calculate how many frames are in this backtrace.
237
+ ptrdiff_t max_backtrace_size;
238
+ if (start_cfp < last_cfp) {
239
+ max_backtrace_size = 0;
240
+ } else {
241
+ max_backtrace_size = start_cfp - last_cfp + 1;
242
+ }
243
+
244
+ *bt_out = mpp_xmalloc(sizeof(struct mpp_rb_backtrace));
245
+ struct mpp_rb_backtrace *bt = *bt_out;
246
+ bt->frame_locations = mpp_xmalloc(sizeof(uint64_t) * max_backtrace_size);
247
+ // Set bt->frames_count to zero, to start with, and only increment it when we see a frame
248
+ // in the backtrace we can actually understand. We might skip over some of them, so max_backtrace_size
249
+ // is a maximum of how many frames there might be in the backtrace.
250
+ bt->frames_count = 0;
251
+ // But do keep track of the memsize
252
+ bt->memsize = sizeof(uint64_t) * max_backtrace_size;
253
+
254
+ ptrdiff_t i;
255
+ const rb_control_frame_t *cfp;
256
+ for (i = 0, cfp = start_cfp; i < max_backtrace_size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
257
+
258
+ // Collect all the information we might need about this frame and store it in this struct
259
+ struct fnloc_st_update_args frame_args;
260
+ frame_args.loctab = loctab;
261
+ if (cfp->iseq && cfp->pc) {
262
+ // I believe means this backtrace frame is ruby code
263
+ size_t iseq_pos = (size_t)(cfp->pc - cfp->iseq->body->iseq_encoded);
264
+ // To quote Ruby:
265
+ // "use pos-1 because PC points next instruction at the beginning of instruction"
266
+ if (iseq_pos) iseq_pos--;
267
+ frame_args.location_line_number = rb_iseq_line_no(cfp->iseq, iseq_pos);
268
+ frame_args.fn_name_value = rb_iseq_method_name(cfp->iseq);
269
+ frame_args.file_name_value = rb_iseq_path(cfp->iseq);
270
+ frame_args.function_line_number = NUM2ULONG(rb_iseq_first_lineno(cfp->iseq));
271
+
272
+ // Use the object ID of the function name (which _should_ be interned, right, and so unique?)
273
+ // as the function ID.
274
+ frame_args.function_id = NUM2ULONG(rb_obj_id(frame_args.fn_name_value));
275
+ // Use the lower 48 bits (which is the sizeof an address on x86_64) of the function name,
276
+ // and the line number in the top 16 bits, as the "location id".
277
+ // Guess this won't work reliably if your function has more than 16k lines, in which case...
278
+ // ...just get a better function?
279
+ frame_args.location_id =
280
+ (frame_args.location_line_number << 48) | (frame_args.function_id & 0x0000FFFFFFFFFFFF);
281
+
282
+ } else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
283
+ // I believe means that this backtrace frame is a call to a cfunc
284
+
285
+
286
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
287
+
288
+ frame_args.location_line_number = 0;
289
+ frame_args.function_line_number = 0;
290
+ frame_args.fn_name_value = rb_id2str(me->def->original_id);
291
+ frame_args.file_name_value = Qnil;
292
+
293
+ // Use the symbol ID of the method name (which is interned forever) as both the function
294
+ // ID and the location ID (since we have no line numbers).
295
+ frame_args.location_id = me->def->original_id;
296
+ frame_args.function_id = me->def->original_id;
297
+ } else {
298
+ // No idea what this means. It's silently ignored in vm_backtrace.c. Guess we will too.
299
+ continue;
300
+ }
301
+
302
+ // Store the location frame.
303
+ bt->frame_locations[bt->frames_count] = frame_args.location_id;
304
+ bt->frames_count++;
305
+
306
+ // Lookup, or allocate & store, the location/function struct.
307
+ st_update(loctab->locations, frame_args.location_id, location_st_update, (st_data_t)&frame_args);
308
+ // Either we created a new one, or looked up an existing one, but either way we need to bump its refcount.
309
+ frame_args.location->refcount++;
310
+ frame_args.function->refcount++;
311
+ }
312
+ }
313
+
314
+ void mpp_rb_backtrace_capture_slowrb(struct mpp_rb_loctab *loctab, struct mpp_rb_backtrace **bt_out) {
315
+ VALUE ruby_bt = rb_funcall(rb_thread_current(), rb_intern("backtrace_locations"), 0);
316
+ int64_t ruby_bt_len = RARRAY_LEN(ruby_bt);
317
+
318
+ *bt_out = mpp_xmalloc(sizeof(struct mpp_rb_backtrace));
319
+ struct mpp_rb_backtrace *bt = *bt_out;
320
+ bt->frame_locations = mpp_xmalloc(sizeof(uint64_t) * ruby_bt_len);
321
+ bt->frames_count = 0;
322
+ bt->memsize = sizeof(uint64_t) * ruby_bt_len;
323
+
324
+ for (int64_t i = 0; i < ruby_bt_len; i++) {
325
+ // The backtrace_locations result is backwards compared to the fast version.
326
+ VALUE ruby_bt_loc = RARRAY_AREF(ruby_bt, ruby_bt_len - i - 1);
327
+
328
+ // Intern the function name as the function ID, and the full string as the loc id.
329
+ VALUE fn_name = rb_funcall(ruby_bt_loc, rb_intern("base_label"), 0);
330
+ const char *fn_name_interned;
331
+ size_t fn_name_interned_len;
332
+ mpp_strtab_intern_rbstr(loctab->strtab, fn_name, &fn_name_interned, &fn_name_interned_len);
333
+ VALUE loc_name = rb_funcall(ruby_bt_loc, rb_intern("to_s"), 0);
334
+ const char *loc_name_interned;
335
+ size_t loc_name_interned_len;
336
+ mpp_strtab_intern_rbstr(loctab->strtab, loc_name, &loc_name_interned, &loc_name_interned_len);
337
+
338
+ VALUE file_name = rb_funcall(ruby_bt_loc, rb_intern("path"), 0);
339
+
340
+ VALUE line_no = rb_funcall(ruby_bt_loc, rb_intern("lineno"), 0);
341
+ uint64_t line_no_int = 0;
342
+ if (RTEST(line_no)) {
343
+ line_no_int = NUM2ULONG(line_no);
344
+ }
345
+
346
+ bt->frame_locations[i] = (uint64_t)loc_name_interned;
347
+ bt->frames_count++;
348
+
349
+ // Lookup, or allocate & store, the location/function struct.
350
+ struct fnloc_st_update_args frame_args;
351
+ frame_args.loctab = loctab;
352
+ frame_args.location_id = (uint64_t)loc_name_interned;
353
+ frame_args.location_line_number = line_no_int;
354
+ frame_args.fn_name_value = fn_name;
355
+ frame_args.file_name_value = file_name;
356
+ frame_args.function_line_number = 0;
357
+ frame_args.function_id = (uint64_t)fn_name_interned;
358
+ st_update(loctab->locations, frame_args.location_id, location_st_update, (st_data_t)&frame_args);
359
+ frame_args.location->refcount++;
360
+ frame_args.function->refcount++;
361
+
362
+ // We _DEFINITELY_ leak memory here. We interned the function name string/location string to use
363
+ // as the unique int64 location ID, but we're not freeing it here. This is because we need to keep
364
+ // it in the table so that it continues to be unique (and some other location doesn't wind up with
365
+ // the same ID).
366
+ // Since this method basically exists for benchmarking, and real users should be using the CFP
367
+ // method, I'll live with the leak for now until I figure out a better unique ID for the function.
368
+ }
369
+ }
370
+
371
+ void mpp_rb_backtrace_destroy(struct mpp_rb_loctab *loctab, struct mpp_rb_backtrace *bt) {
372
+ for (int64_t i = 0; i < bt->frames_count; i++) {
373
+ st_update(loctab->locations, bt->frame_locations[i], location_st_deref, (st_data_t)loctab);
374
+ }
375
+ mpp_free(bt->frame_locations);
376
+ mpp_free(bt);
377
+ }
378
+
379
+ size_t mpp_rb_backtrace_memsize(struct mpp_rb_backtrace *bt) {
380
+ return bt->memsize;
381
+ }
382
+
383
+ size_t mpp_rb_loctab_memsize(struct mpp_rb_loctab *loctab) {
384
+ return sizeof(*loctab) +
385
+ sizeof(struct mpp_rb_loctab_location) * loctab->location_count +
386
+ sizeof(struct mpp_rb_loctab_function) * loctab->function_count +
387
+ st_memsize(loctab->locations) +
388
+ st_memsize(loctab->functions);
389
+ }
390
+
391
+ struct mpp_rb_loctab_each_location_ctx {
392
+ mpp_rb_loctab_each_location_cb cb;
393
+ void *cb_ctx;
394
+ struct mpp_rb_loctab *loctab;
395
+ };
396
+
397
+ static int mpp_rb_loctab_each_location_thunk(st_data_t key, st_data_t value, st_data_t ctx) {
398
+ struct mpp_rb_loctab_each_location_ctx * thunkctx = (struct mpp_rb_loctab_each_location_ctx *)ctx;
399
+ struct mpp_rb_loctab_location *loc = (struct mpp_rb_loctab_location *)value;
400
+ return thunkctx->cb(thunkctx->loctab, loc, thunkctx->cb_ctx);
401
+ }
402
+
403
+ void mpp_rb_loctab_each_location(struct mpp_rb_loctab *loctab, mpp_rb_loctab_each_location_cb cb, void *ctx) {
404
+ struct mpp_rb_loctab_each_location_ctx thunkctx;
405
+ thunkctx.loctab = loctab;
406
+ thunkctx.cb = cb;
407
+ thunkctx.cb_ctx = ctx;
408
+ st_foreach(loctab->locations, mpp_rb_loctab_each_location_thunk, (st_data_t)&thunkctx);
409
+ }
410
+
411
+ struct mpp_rb_loctab_each_function_ctx {
412
+ mpp_rb_loctab_each_function_cb cb;
413
+ void *cb_ctx;
414
+ struct mpp_rb_loctab *loctab;
415
+ };
416
+
417
+ static int mpp_rb_loctab_each_function_thunk(st_data_t key, st_data_t value, st_data_t ctx) {
418
+ struct mpp_rb_loctab_each_function_ctx * thunkctx = (struct mpp_rb_loctab_each_function_ctx *)ctx;
419
+ struct mpp_rb_loctab_function *loc = (struct mpp_rb_loctab_function *)value;
420
+ return thunkctx->cb(thunkctx->loctab, loc, thunkctx->cb_ctx);
421
+ }
422
+
423
+ void mpp_rb_loctab_each_function(struct mpp_rb_loctab *loctab, mpp_rb_loctab_each_function_cb cb, void *ctx) {
424
+ struct mpp_rb_loctab_each_function_ctx thunkctx;
425
+ thunkctx.loctab = loctab;
426
+ thunkctx.cb = cb;
427
+ thunkctx.cb_ctx = ctx;
428
+ st_foreach(loctab->functions, mpp_rb_loctab_each_function_thunk, (st_data_t)&thunkctx);
429
+ }