ruby_memprofiler_pprof 0.0.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.
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
+ }