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
@@ -0,0 +1,391 @@
1
+ #include <pthread.h>
2
+ #include <string.h>
3
+
4
+ #include <ruby.h>
5
+ #include "ruby_memprofiler_pprof.h"
6
+
7
+
8
+ static int mpp_strtab_strcompare(st_data_t arg1, st_data_t arg2) {
9
+ struct mpp_strtab_key *k1 = (struct mpp_strtab_key *)arg1;
10
+ struct mpp_strtab_key *k2 = (struct mpp_strtab_key *)arg2;
11
+
12
+ size_t smaller_len = (k1->str_len > k2->str_len) ? k2->str_len : k1->str_len;
13
+ int cmp = memcmp(k1->str, k2->str, smaller_len);
14
+
15
+ if (cmp != 0 || k1->str_len == k2->str_len) {
16
+ // Either: one of the first smaller_len bytes were different, or
17
+ // they were the same, AND the lenghts are the same, which make them the same string.
18
+ return cmp;
19
+ }
20
+ // The first smaller_len bytes are the same, but one is longer than the other.
21
+ // The shorter string should be considered smaller.
22
+ return k1->str_len > k2->str_len ? 1 : -1;
23
+ }
24
+
25
+ static st_index_t mpp_strtab_strhash(st_data_t arg) {
26
+ struct mpp_strtab_key *k = (struct mpp_strtab_key *)arg;
27
+ return st_hash(k->str, k->str_len, FNV1_32A_INIT);
28
+ }
29
+
30
+ static const struct st_hash_type mpp_strtab_hash_type = {
31
+ .compare = mpp_strtab_strcompare,
32
+ .hash = mpp_strtab_strhash,
33
+ };
34
+
35
+ // Frees the memory associated with a single struct str_intern_tab_el
36
+ static void mpp_strtab_free_intern_tab_el(struct mpp_strtab_el *el) {
37
+ mpp_free(el->str);
38
+ mpp_free(el);
39
+ }
40
+
41
+ struct mpp_strtab_table_extract_els_args {
42
+ struct mpp_strtab_el **el_ary;
43
+ int64_t el_ary_len;
44
+ int64_t el_ary_cur_ix;
45
+ int should_delete;
46
+ };
47
+
48
+ // Used in st_foreach to extract every table element to an array. If arg has should_delete set, then
49
+ // this will also remove it from the table too.
50
+ static int mpp_strtab_table_extract_els(st_data_t key, st_data_t value, st_data_t arg) {
51
+ struct mpp_strtab_el *el = (struct mpp_strtab_el *)value;
52
+ struct mpp_strtab_table_extract_els_args *args = (struct mpp_strtab_table_extract_els_args *)arg;
53
+
54
+ MPP_ASSERT_MSG(
55
+ args->el_ary_cur_ix < args->el_ary_len,
56
+ "strtab: array passed in to mpp_strtab_table_extract_els not big enough?"
57
+ );
58
+
59
+ args->el_ary[args->el_ary_cur_ix] = el;
60
+ args->el_ary_cur_ix++;
61
+
62
+ return args->should_delete ? ST_DELETE : ST_CONTINUE;
63
+ }
64
+
65
+ struct mpp_strtab_table_decrement_el_refcount_args {
66
+ struct mpp_strtab_el *el;
67
+ };
68
+
69
+ // Used in st_update to decrement the refcount of a table entry; if the refcount drops to zero, the
70
+ // struct str_intern_tab_el is freed and the entry removed from the table.
71
+ static int mpp_strtab_table_decrement_el_refcount(st_data_t *key, st_data_t *value, st_data_t arg, int existing) {
72
+ MPP_ASSERT_MSG(existing && value, "strtab: attempted to decrement refcount on non-present element");
73
+ struct mpp_strtab_el *el = (struct mpp_strtab_el *)*value;
74
+
75
+ // We need to store the value we are operating on back in the *args array, so our caller can free the element
76
+ // if its refcount dropped to zero.
77
+ struct mpp_strtab_table_decrement_el_refcount_args *args = (struct mpp_strtab_table_decrement_el_refcount_args *)arg;
78
+ args->el = el;
79
+
80
+ MPP_ASSERT_MSG(el->refcount > 0, "strtab: attempted to decrement refcount below zero");
81
+ el->refcount--;
82
+
83
+ // Remvoe it from the table if it was the last reference.
84
+ return el->refcount == 0 ? ST_DELETE : ST_CONTINUE;
85
+ }
86
+
87
+ // Allocates and configures a struct str_intern_tab.
88
+ struct mpp_strtab *mpp_strtab_new() {
89
+ struct mpp_strtab *tab = mpp_xmalloc(sizeof(struct mpp_strtab));
90
+ tab->table = st_init_table(&mpp_strtab_hash_type);
91
+ tab->table_count = 0;
92
+ tab->table_entry_size = 0;
93
+
94
+ // According to pprof rules, every string table needs ""
95
+ mpp_strtab_intern(tab, "", 0, &tab->interned_empty_str, NULL);
96
+
97
+ return tab;
98
+ }
99
+
100
+ // Immediately frees all memory held by *tab. After this call, any referneces to interned strings outside
101
+ // of this module are dangling. Also frees *tab itself.
102
+ void mpp_strtab_destroy(struct mpp_strtab *tab) {
103
+
104
+ // We need to first copy all the elements of the table into an array, and _then_ remove them from the table,
105
+ // and only then free the elements. This is because we use the element str pointer as the key of the table,
106
+ // and freeing that before removing the element from the table would mean that it would do some use-after-free.
107
+ struct mpp_strtab_table_extract_els_args table_loop_args;
108
+ table_loop_args.should_delete = 1;
109
+ table_loop_args.el_ary_cur_ix = 0;
110
+ table_loop_args.el_ary_len = tab->table_count;
111
+ table_loop_args.el_ary = mpp_xmalloc(tab->table_count * sizeof(struct mpp_strtab_el *));
112
+ st_foreach(tab->table, mpp_strtab_table_extract_els, (st_data_t)&table_loop_args);
113
+
114
+ // Now we can free the table elements themselves, and the memory they hold
115
+ for (int64_t i = 0; i < table_loop_args.el_ary_len; i++) {
116
+ tab->table_count--;
117
+ tab->table_entry_size -= sizeof(struct mpp_strtab_el) + table_loop_args.el_ary[i]->str_len + 1;
118
+ mpp_strtab_free_intern_tab_el(table_loop_args.el_ary[i]);
119
+ }
120
+ mpp_free(table_loop_args.el_ary);
121
+
122
+ // And _now_ it's finally OK to delete the table itself.
123
+ st_free_table(tab->table);
124
+ mpp_free(tab);
125
+ }
126
+
127
+ // Get the memory size of the table, for use in reporting the struct memsize to Ruby.
128
+ // Does NOT include sizeof(tab).
129
+ size_t mpp_strtab_memsize(struct mpp_strtab *tab) {
130
+ return st_memsize(tab->table) + tab->table_entry_size;
131
+ }
132
+
133
+ // Implementation for interning a string. Interns the string str, and writes the interned string pointer to
134
+ // *interned_str_out and the length (not including null terminator) to *interned_str_len_out.
135
+ static void mpp_strtab_intern_impl(
136
+ struct mpp_strtab *tab, const char *str, int str_len,
137
+ const char **interned_str_out, size_t *interned_str_len_out
138
+ ) {
139
+ // Consider interning a NULL string as the same as an "" empty string.
140
+ if (!str) {
141
+ str = "";
142
+ }
143
+
144
+ // First - is str already in the table?
145
+ struct mpp_strtab_el *interned_value;
146
+ struct mpp_strtab_key lookup_key = {
147
+ .str = str,
148
+ .str_len = str_len,
149
+ };
150
+ if (st_lookup(tab->table, (st_data_t)&lookup_key, (st_data_t *)&interned_value)) {
151
+ // Yes it is. Increment its refcount and return its interned value.
152
+ interned_value->refcount++;
153
+ *interned_str_out = interned_value->str;
154
+ if (interned_str_len_out) {
155
+ *interned_str_len_out = interned_value->str_len;
156
+ }
157
+ return;
158
+ }
159
+
160
+ // It's not - we need to intern it then.
161
+ interned_value = mpp_xmalloc(sizeof(struct mpp_strtab_el));
162
+ // We always intern a _copy_ of the string, so that the caller is free to dispose of str as they will.
163
+ // We also null-terminate our copy, since that's convenient and free for us to do at this point.
164
+ interned_value->str_len = str_len;
165
+ interned_value->str = mpp_xmalloc(interned_value->str_len + 1);
166
+ memcpy(interned_value->str, str, interned_value->str_len);
167
+ interned_value->str[interned_value->str_len] = '\0';
168
+
169
+ // The key is actually embedded in the value. Set it up.
170
+ interned_value->key.str_len = interned_value->str_len;
171
+ interned_value->key.str = interned_value->str;
172
+
173
+ // Refcount starts at one (from this call)
174
+ interned_value->refcount = 1;
175
+
176
+ int r = st_insert(tab->table, (st_data_t)&interned_value->key, (st_data_t)interned_value);
177
+ MPP_ASSERT_MSG(r == 0, "strtab: attempted to overwrite intern entry");
178
+
179
+ tab->table_count++;
180
+ tab->table_entry_size += sizeof(*interned_value) + interned_value->str_len + 1;
181
+ *interned_str_out = interned_value->str;
182
+ if (interned_str_len_out) {
183
+ *interned_str_len_out = interned_value->str_len;
184
+ }
185
+ }
186
+
187
+ // Interns the string str into this string table, writing an interned pointer to the string to interned_str_out.
188
+ // Notes:
189
+ // - str need not be null terminated.
190
+ // - str_len is the length of str, NOT INCLUDING any null termination.
191
+ // - Alternatively, if str_len is MPP_STRTAB_USE_STRLEN, then it is calculated by calling strlen(str) (and
192
+ // thus in this case, str MUST be null-terminated). This is really only designed for interning literals.
193
+ // - Retains no reference to str; it's copied if needed. The caller is free to do what they wish with
194
+ // str after this method returns.
195
+ // - The returned *interned_str_out IS null terminated.
196
+ // - The returned *interned_str_len_out is the length of *interned_str_out, NOT INCLUDING the null
197
+ // termination.
198
+ void mpp_strtab_intern(
199
+ struct mpp_strtab *tab, const char *str, int str_len,
200
+ const char **interned_str_out, size_t *interned_str_len_out
201
+ ) {
202
+ if (str_len == MPP_STRTAB_USE_STRLEN) {
203
+ str_len = (int)strlen(str);
204
+ }
205
+ mpp_strtab_intern_impl(tab, str, str_len, interned_str_out, interned_str_len_out);
206
+ }
207
+
208
+ // Does what mpp_strtab_intern does, but calculates the length from strlen()
209
+ void mpp_strtab_intern_cstr(
210
+ struct mpp_strtab *tab, const char *str, const char **interned_str_out, size_t *interned_str_len_out
211
+ ) {
212
+ int str_len = (int)strlen(str);
213
+ mpp_strtab_intern_impl(tab, str, str_len, interned_str_out, interned_str_len_out);
214
+ }
215
+
216
+ static VALUE mpp_strtab_stringify_value(VALUE val) {
217
+ return rb_sprintf("%"PRIsVALUE, val);
218
+ }
219
+
220
+ static void mpp_strtab_rbstr_to_tmpstr(VALUE rbstr, const char **str, int *str_len) {
221
+ VALUE to_s_val;
222
+ if (RB_TYPE_P(rbstr, RUBY_T_STRING)) {
223
+ // Already a string.
224
+ to_s_val = rbstr;
225
+ } else {
226
+ // Try and convert it.
227
+ int tag = 0;
228
+ VALUE original_ex = rb_errinfo();
229
+ to_s_val = rb_protect(mpp_strtab_stringify_value, rbstr, &tag);
230
+ if (tag) {
231
+ // it threw. Make sure rb_erroinfo wasn't clobbered.
232
+ rb_set_errinfo(original_ex);
233
+ to_s_val = Qundef;
234
+ }
235
+ }
236
+
237
+ if (RB_TYPE_P(to_s_val, RUBY_T_STRING)) {
238
+ *str = RSTRING_PTR(to_s_val);
239
+ *str_len = (int) RSTRING_LEN(to_s_val);
240
+ } else {
241
+ // to_s returned a non-string.
242
+ *str = MPP_STRTAB_UNKNOWN_LITERAL;
243
+ *str_len = MPP_STRTAB_UNKNOWN_LITERAL_LEN;
244
+ }
245
+ }
246
+
247
+
248
+ // Interns the Ruby string rbstr into the table, copying it to native memory if required. Writes the interned
249
+ // pointer to a null-terminated c string *interned_str_out and the length (not including null terminator)
250
+ // to *interned_str_len_out.
251
+ // Notes:
252
+ // - This will work fine even if rbstr has NULLs in it.
253
+ // - Will convert rbstr to a char * via the following process:
254
+ // - If it's an RSTRING, just use its value
255
+ // - Otherwise, call #to_s on it, and use that value if that's an RSTRING.
256
+ // - Otherwise, use a built-in default string.
257
+ // - Retains no reference to rbstr; it's copied if needed. The caller is free to do what they wish with
258
+ // str after this method returns.
259
+ // - The returned *interned_str_out IS null terminated.
260
+ // - The returned *interned_str_len_out is the length of *interned_str_out, NOT INCLUDING the null
261
+ // termination.
262
+ // - This needs to be called under the GVL, obviously, because it's using Ruby VALUEs.
263
+ void mpp_strtab_intern_rbstr(
264
+ struct mpp_strtab *tab, VALUE rbstr,
265
+ const char **interned_str_out, size_t *interned_str_len_out
266
+ ) {
267
+ const char *str;
268
+ int str_len;
269
+ mpp_strtab_rbstr_to_tmpstr(rbstr, &str, &str_len);
270
+ mpp_strtab_intern(tab, str, str_len, interned_str_out, interned_str_len_out);
271
+ }
272
+
273
+ static void mpp_strtab_release_by_key(struct mpp_strtab *tab, struct mpp_strtab_key lookup_key) {
274
+ struct mpp_strtab_table_decrement_el_refcount_args cb_args;
275
+ cb_args.el = NULL;
276
+ st_update(tab->table, (st_data_t)&lookup_key, mpp_strtab_table_decrement_el_refcount, (st_data_t)&cb_args);
277
+
278
+ // If the found element had its refcount dropped to zero, free it; note that this _MUST_ happen _AFTER_
279
+ // removing it from the table, because we use the str pointer on the element as the key in the table and
280
+ // the comparison function will read freed memory if we free it before removing it.
281
+ MPP_ASSERT_MSG(cb_args.el, "strtab: did not write the updated element to cb_args.el?");
282
+ if (cb_args.el->refcount == 0) {
283
+ tab->table_count--;
284
+ tab->table_entry_size -= sizeof(*cb_args.el) + cb_args.el->str_len + 1;
285
+ mpp_strtab_free_intern_tab_el(cb_args.el);
286
+ }
287
+ }
288
+
289
+ // Releases a reference to the string str in the intern table;
290
+ void mpp_strtab_release(struct mpp_strtab *tab, const char *str, size_t str_len) {
291
+ // Consider interning a NULL string as the same as an "" empty string.
292
+ if (!str) {
293
+ str = "";
294
+ }
295
+
296
+ struct mpp_strtab_key lookup_key = {
297
+ .str = str,
298
+ .str_len = str_len,
299
+ };
300
+ mpp_strtab_release_by_key(tab, lookup_key);
301
+ }
302
+
303
+ // Releases a reference to a ruby string str in the intern table; see mpp_strtab_intern_rbstr for details on how
304
+ // the conversion from VALUE to char * is done.
305
+ void mpp_strtab_release_rbstr(struct mpp_strtab *tab, VALUE rbstr) {
306
+ const char *str;
307
+ int str_len;
308
+ mpp_strtab_rbstr_to_tmpstr(rbstr, &str, &str_len);
309
+ mpp_strtab_release(tab, str, str_len);
310
+ }
311
+
312
+ // Creates a zero-based "list index" of the current contents of tab and stores it in *ix_out.
313
+ // This "list index" can be used to turn interned pointers into zero-based ordinals into the
314
+ // index as requried by the pprof protobuf format.
315
+ // Once the index structure is created, it is safe to use this structure concurrently with the
316
+ // table itself (i.e. so samples can continue to be collected in the profiler).
317
+ // Note that it is NOT safe to destroy the index concurrently with table use however.
318
+ struct mpp_strtab_index *mpp_strtab_index(struct mpp_strtab *tab) {
319
+ struct mpp_strtab_index *ix = mpp_xmalloc(sizeof(struct mpp_strtab_index));
320
+
321
+ // Accumulate a pointer to every element.
322
+ struct mpp_strtab_table_extract_els_args table_loop_args;
323
+ table_loop_args.should_delete = 0;
324
+ table_loop_args.el_ary_cur_ix = 0;
325
+ table_loop_args.el_ary_len = tab->table_count;
326
+ table_loop_args.el_ary = mpp_xmalloc(tab->table_count * sizeof(struct mpp_strtab_el *));
327
+ st_foreach(tab->table, mpp_strtab_table_extract_els, (st_data_t)&table_loop_args);
328
+
329
+ // Just save the list straight on the index - the index owns that now.
330
+ ix->str_list = table_loop_args.el_ary;
331
+ ix->str_list_len = table_loop_args.el_ary_len;
332
+ ix->pos_table = st_init_numtable();
333
+ ix->tab = tab;
334
+
335
+ // According to pprof rules, every string table needs to have "" at position zero for some reason.
336
+ // Keep track of where "" winds up so we can swap it afterwards intl position 0.
337
+ int64_t emptystr_index = -1;
338
+
339
+ for (int64_t i = 0; i < ix->str_list_len; i++) {
340
+ struct mpp_strtab_el *el = ix->str_list[i];
341
+ // Retain one on the refcount for each element that was saved, so they can't
342
+ // be freed until we're done with them.
343
+ el->refcount++;
344
+
345
+ // Insert it into the interned ptr table.
346
+ int r = st_insert(ix->pos_table, (st_data_t)el->str, i);
347
+ MPP_ASSERT_MSG(r == 0, "strtab: duplicate entry while building pos_table?");
348
+ if (el->str == tab->interned_empty_str) {
349
+ emptystr_index = i;
350
+ }
351
+ }
352
+
353
+
354
+ // Swap whatever's in 0 with wherever "" is.
355
+ MPP_ASSERT_MSG(emptystr_index >= 0, "strtab: empty was not present while building pos_table?");
356
+ struct mpp_strtab_el *tmp = ix->str_list[0];
357
+ ix->str_list[0] = ix->str_list[emptystr_index];
358
+ ix->str_list[emptystr_index] = tmp;
359
+ // st_insert also does update!
360
+ st_insert(ix->pos_table, (st_data_t)tab->interned_empty_str, 0);
361
+ st_insert(ix->pos_table, (st_data_t)tmp->str, emptystr_index);
362
+
363
+ return ix;
364
+ }
365
+
366
+ // Destroys a previously created index. Must not be called concurrently with any other method on
367
+ // the stringtab or index. Does NOT free the memory ix itself.
368
+ void mpp_strtab_index_destroy(struct mpp_strtab_index *ix) {
369
+ // As far as st_hash is concerned, ix->pos_table is just a mapping of numbers -> numbers; it does
370
+ // not dereference the pointers in any way, so it's safe to just destroy the hash right off the bat
371
+ // without carefully removing the elements first, unlike tab->table.
372
+ st_free_table(ix->pos_table);
373
+
374
+ // Decrement refcounts & maybe free them from the underlying tab.
375
+ for (int64_t i = 0; i < ix->str_list_len; i++) {
376
+ struct mpp_strtab_el *el = ix->str_list[i];
377
+ mpp_strtab_release_by_key(ix->tab, el->key);
378
+ }
379
+
380
+ mpp_free(ix->str_list);
381
+ }
382
+
383
+ // Returns the index of the provided interned pointer in our list, or else -1.
384
+ int64_t mpp_strtab_index_of(struct mpp_strtab_index *ix, const char *interned_ptr) {
385
+ int64_t found_index;
386
+ int r = st_lookup(ix->pos_table, (st_data_t)interned_ptr, (st_data_t *)&found_index);
387
+ if (!r) {
388
+ return -1;
389
+ }
390
+ return found_index;
391
+ }