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,285 @@
1
+ #include <ruby.h>
2
+ #include <zlib.h>
3
+
4
+ #include "ruby_memprofiler_pprof.h"
5
+
6
+ // allocator/free function for our upb_arena. Contract is:
7
+ // If "size" is 0 then the function acts like free(), otherwise it acts like
8
+ // realloc(). Only "oldsize" bytes from a previous allocation are preserved.
9
+ static void *mpp_pprof_upb_arena_malloc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) {
10
+ if (size == 0) {
11
+ mpp_free(ptr);
12
+ return NULL;
13
+ } else {
14
+ return mpp_realloc(ptr, size);
15
+ }
16
+ }
17
+
18
+ // Initialize an already-allocated serialization context.
19
+ struct mpp_pprof_serctx *mpp_pprof_serctx_new() {
20
+ struct mpp_pprof_serctx *ctx = mpp_xmalloc(sizeof(struct mpp_pprof_serctx));
21
+ ctx->allocator.func = mpp_pprof_upb_arena_malloc;
22
+ ctx->arena = upb_Arena_Init(NULL, 0, &ctx->allocator);
23
+ ctx->profile_proto = perftools_profiles_Profile_new(ctx->arena);
24
+ ctx->strindex = NULL;
25
+ return ctx;
26
+ }
27
+
28
+ // Destroys the serialization context. After this call, any stringtab indexes it held
29
+ // are released, and any memory from its internal state is freed. *ctx itself is also
30
+ // freed and must not be dereferenced after this.
31
+ void mpp_pprof_serctx_destroy(struct mpp_pprof_serctx *ctx) {
32
+ upb_Arena_Free(ctx->arena);
33
+ if (ctx->strindex) {
34
+ mpp_strtab_index_destroy(ctx->strindex);
35
+ }
36
+ mpp_free(ctx);
37
+ }
38
+
39
+
40
+ struct mpp_pprof_serctx_add_location_ctx {
41
+ struct mpp_pprof_serctx *ctx;
42
+ int is_error;
43
+ char *errbuf;
44
+ size_t errbuflen;
45
+ };
46
+
47
+ static int mpp_pprof_serctx_add_location(
48
+ struct mpp_rb_loctab *loctab, struct mpp_rb_loctab_location *location, void *ctx
49
+ ) {
50
+ struct mpp_pprof_serctx_add_location_ctx *thunkctx = ctx;
51
+ struct perftools_profiles_Location *loc_proto = perftools_profiles_Profile_add_location(thunkctx->ctx->profile_proto, thunkctx->ctx->arena);
52
+
53
+
54
+ perftools_profiles_Location_set_id(loc_proto, location->id);
55
+ perftools_profiles_Line *line_proto = perftools_profiles_Location_add_line(loc_proto, thunkctx->ctx->arena);
56
+ perftools_profiles_Line_set_function_id(line_proto, location->function->id);
57
+ perftools_profiles_Line_set_line(line_proto, location->line_number);
58
+
59
+ return ST_CONTINUE;
60
+ }
61
+
62
+ struct mpp_pprof_serctx_add_function_ctx {
63
+ struct mpp_pprof_serctx *ctx;
64
+ int is_error;
65
+ char *errbuf;
66
+ size_t errbuflen;
67
+ };
68
+
69
+ static int mpp_pprof_serctx_add_function(
70
+ struct mpp_rb_loctab *loctab, struct mpp_rb_loctab_function *function, void *ctx
71
+ ) {
72
+ struct mpp_pprof_serctx_add_function_ctx *thunkctx = ctx;
73
+ struct perftools_profiles_Function *fn_proto = perftools_profiles_Profile_add_function(thunkctx->ctx->profile_proto, thunkctx->ctx->arena);
74
+
75
+ perftools_profiles_Function_set_id(fn_proto, function->id);
76
+
77
+ #define FN_SET_STRINTERN_FIELD(field, str) \
78
+ do { \
79
+ int64_t interned = mpp_strtab_index_of(thunkctx->ctx->strindex, (str)); \
80
+ if (interned == -1) { \
81
+ ruby_snprintf( \
82
+ thunkctx->errbuf, thunkctx->errbuflen, \
83
+ "non-interned string %s passed for Function.#field", (str) \
84
+ ); \
85
+ return -1; \
86
+ } \
87
+ perftools_profiles_Function_set_##field(fn_proto, interned); \
88
+ } while (0)
89
+
90
+ FN_SET_STRINTERN_FIELD(name, function->function_name);
91
+ FN_SET_STRINTERN_FIELD(system_name, function->function_name);
92
+ FN_SET_STRINTERN_FIELD(filename, function->file_name);
93
+
94
+ #undef FN_SET_STRINTERN_FIELD
95
+
96
+
97
+ return ST_CONTINUE;
98
+ }
99
+
100
+
101
+ // This method is used to set the location table used in backtrace samples to be added
102
+ //
103
+ // This method will actually take a reference to all relevant strings currently in loctab->strtab via
104
+ // a call to mpp_strtab_index; thus, after this method returns, it is safe for another thread to
105
+ // continue using the stringtab because we have what we need in our index.
106
+ int mpp_pprof_serctx_set_loctab(
107
+ struct mpp_pprof_serctx *ctx, struct mpp_rb_loctab *loctab, char *errbuf, size_t errbuflen
108
+ ) {
109
+ ctx->loctab = loctab;
110
+
111
+ // Intern some strings we'll need to produce our output
112
+ mpp_strtab_intern_cstr(loctab->strtab, "allocations", &ctx->internstr_allocations, NULL);
113
+ mpp_strtab_intern_cstr(loctab->strtab, "count", &ctx->internstr_count, NULL);
114
+ mpp_strtab_intern_cstr(loctab->strtab, "allocation_size", &ctx->internstr_allocation_size, NULL);
115
+ mpp_strtab_intern_cstr(loctab->strtab, "bytes", &ctx->internstr_bytes, NULL);
116
+ mpp_strtab_intern_cstr(loctab->strtab, "retained_objects", &ctx->internstr_retained_objects, NULL);
117
+ mpp_strtab_intern_cstr(loctab->strtab, "retained_size", &ctx->internstr_retained_size, NULL);
118
+
119
+ ctx->strindex = mpp_strtab_index(loctab->strtab);
120
+ MPP_ASSERT_MSG(ctx->strindex, "mpp_strtab_index returned 0");
121
+
122
+ // Set up the string table in the protobuf
123
+ upb_StringView *stringtab_list_proto =
124
+ perftools_profiles_Profile_resize_string_table(ctx->profile_proto, ctx->strindex->str_list_len, ctx->arena);
125
+ for (int64_t i = 0; i < ctx->strindex->str_list_len; i++) {
126
+ upb_StringView *stringtab_proto = &stringtab_list_proto[i];
127
+ struct mpp_strtab_el *intern_tab_el = ctx->strindex->str_list[i];
128
+ stringtab_proto->data = intern_tab_el->str;
129
+ stringtab_proto->size = intern_tab_el->str_len;
130
+ }
131
+
132
+ // Set up the sample types etc.
133
+ perftools_profiles_ValueType *allocations_vt =
134
+ perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
135
+ perftools_profiles_ValueType *allocation_size_vt =
136
+ perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
137
+ perftools_profiles_ValueType *retained_objects_vt =
138
+ perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
139
+ perftools_profiles_ValueType *retained_size_vt =
140
+ perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
141
+ #define VT_SET_STRINTERN_FIELD(vt, field, str) \
142
+ do { \
143
+ int64_t interned = mpp_strtab_index_of(ctx->strindex, (str)); \
144
+ if (interned == -1) { \
145
+ ruby_snprintf(errbuf, errbuflen, "non-interned string %s passed for ValueType.#field", (str)); \
146
+ return -1; \
147
+ } \
148
+ perftools_profiles_ValueType_set_##field(vt, interned); \
149
+ } while (0)
150
+
151
+ VT_SET_STRINTERN_FIELD(allocations_vt, type, ctx->internstr_allocations);
152
+ VT_SET_STRINTERN_FIELD(allocations_vt, unit, ctx->internstr_count);
153
+ VT_SET_STRINTERN_FIELD(allocation_size_vt, type, ctx->internstr_allocation_size);
154
+ VT_SET_STRINTERN_FIELD(allocation_size_vt, unit, ctx->internstr_bytes);
155
+ VT_SET_STRINTERN_FIELD(retained_objects_vt, type, ctx->internstr_retained_objects);
156
+ VT_SET_STRINTERN_FIELD(retained_objects_vt, unit, ctx->internstr_count);
157
+ VT_SET_STRINTERN_FIELD(retained_size_vt, type, ctx->internstr_retained_size);
158
+ VT_SET_STRINTERN_FIELD(retained_size_vt, unit, ctx->internstr_bytes);
159
+ #undef VT_SET_STRINTERN_FIELD
160
+
161
+ // Set up the location array.
162
+ struct mpp_pprof_serctx_add_location_ctx loc_add_ctx;
163
+ loc_add_ctx.ctx = ctx;
164
+ loc_add_ctx.errbuf = errbuf;
165
+ loc_add_ctx.errbuflen = errbuflen;
166
+ loc_add_ctx.is_error = 0;
167
+ mpp_rb_loctab_each_location(ctx->loctab, mpp_pprof_serctx_add_location, &loc_add_ctx);
168
+ if (loc_add_ctx.is_error) {
169
+ return -1;
170
+ }
171
+
172
+ // And the same for functions pretty much
173
+ struct mpp_pprof_serctx_add_function_ctx fn_add_ctx;
174
+ fn_add_ctx.ctx = ctx;
175
+ fn_add_ctx.errbuf = errbuf;
176
+ fn_add_ctx.errbuflen = errbuflen;
177
+ fn_add_ctx.is_error = 0;
178
+ mpp_rb_loctab_each_function(ctx->loctab, mpp_pprof_serctx_add_function, &fn_add_ctx);
179
+ if (loc_add_ctx.is_error) {
180
+ return -1;
181
+ }
182
+
183
+ return 0;
184
+ }
185
+
186
+ int mpp_pprof_serctx_add_sample(
187
+ struct mpp_pprof_serctx *ctx, struct mpp_sample *sample, int sample_type, char *errbuf, size_t errbuflen
188
+ ) {
189
+ perftools_profiles_Sample *sample_proto = perftools_profiles_Profile_add_sample(ctx->profile_proto, ctx->arena);
190
+ uint64_t *location_ids =
191
+ perftools_profiles_Sample_resize_location_id(sample_proto, sample->bt->frames_count, ctx->arena);
192
+
193
+ // We need to iterate through this backtrace backwards; Ruby makes it easy for us to get this backtrace
194
+ // in most-recent-call-last format, but pprof wants most-recent-call-first.
195
+ for (int64_t i = 0; i < sample->bt->frames_count; i++) {
196
+ location_ids[i] = sample->bt->frame_locations[sample->bt->frames_count - i - 1];
197
+ }
198
+
199
+ // Values are (allocation_count, allocation_size, retained_count, retained_size).
200
+ int64_t allocation_count = 0;
201
+ int64_t allocation_size = 0;
202
+ int64_t retained_count = 0;
203
+ int64_t retained_size = 0;
204
+ if (sample_type == MPP_SAMPLE_TYPE_ALLOCATION) {
205
+ allocation_count = 1;
206
+ allocation_size = (int64_t)sample->allocation_size;
207
+ }
208
+ if (sample_type == MPP_SAMPLE_TYPE_HEAP) {
209
+ retained_count = 1;
210
+ retained_size = (int64_t)sample->current_size;
211
+ }
212
+ perftools_profiles_Sample_add_value(sample_proto, allocation_count, ctx->arena);
213
+ perftools_profiles_Sample_add_value(sample_proto, allocation_size, ctx->arena);
214
+ perftools_profiles_Sample_add_value(sample_proto, retained_count, ctx->arena);
215
+ perftools_profiles_Sample_add_value(sample_proto, retained_size, ctx->arena);
216
+ return 0;
217
+ }
218
+
219
+ // Serializes the contained protobuf, and gzips the result. Writes a pointer to the memory in *buf_out,
220
+ // and its length to buflen_out. The returned pointer is freed when mpp_pprof_serctx_destroy() is called,
221
+ // and should NOT be individually freed by the caller in any way (and nor is it valid after the call
222
+ // to destroy()).
223
+ int mpp_pprof_serctx_serialize(
224
+ struct mpp_pprof_serctx *ctx, char **buf_out, size_t *buflen_out, char *errbuf, size_t errbuflen
225
+ ) {
226
+ // It looks like some codepaths might leak the protobuf_data pointer, but that's OK - it's in
227
+ // the ctx->arena so it'll get freed when ctx does.
228
+ size_t protobuf_data_len;
229
+ char *protobuf_data = perftools_profiles_Profile_serialize(ctx->profile_proto, ctx->arena, &protobuf_data_len);
230
+
231
+ // Gzip it as per standard.
232
+ z_stream strm;
233
+ int r;
234
+ int retval = 0;
235
+
236
+ strm.zalloc = Z_NULL;
237
+ strm.zfree = Z_NULL;
238
+ strm.opaque = Z_NULL;
239
+ strm.msg = NULL;
240
+ int windowBits = 15;
241
+ int GZIP_ENCODING = 16;
242
+ r = deflateInit2(
243
+ &strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
244
+ windowBits | GZIP_ENCODING, 8, Z_DEFAULT_STRATEGY
245
+ );
246
+ if (r != Z_OK) {
247
+ ruby_snprintf(errbuf, errbuflen, "error initializing zlib (errno %d: %s)", r, strm.msg ?: "");
248
+ return -1;
249
+ }
250
+ strm.avail_in = (unsigned int)protobuf_data_len;
251
+ strm.next_in = (unsigned char *)protobuf_data;
252
+
253
+ const size_t out_chunk_size = 4096;
254
+ char *gzip_data = upb_Arena_Malloc(ctx->arena, out_chunk_size);
255
+ size_t gzip_data_allocd_len = out_chunk_size;
256
+ strm.avail_out = out_chunk_size;
257
+ strm.next_out = (unsigned char *)gzip_data;
258
+ while(true) {
259
+ int flush = strm.avail_in == 0 ? Z_FINISH : Z_NO_FLUSH;
260
+ r = deflate(&strm, flush);
261
+ if (r == Z_STREAM_END) {
262
+ break;
263
+ } else if (r != Z_OK) {
264
+ // uh wat?
265
+ ruby_snprintf(errbuf, errbuflen, "error doing zlib output (errno %d: %s)", r, strm.msg ?: "");
266
+ retval = -1;
267
+ goto zstream_free;
268
+ }
269
+
270
+ if (strm.avail_out == 0) {
271
+ size_t old_gzip_data_allocd_len = gzip_data_allocd_len;
272
+ gzip_data_allocd_len += out_chunk_size;
273
+ gzip_data = upb_Arena_Realloc(ctx->arena, gzip_data, old_gzip_data_allocd_len, gzip_data_allocd_len);
274
+ strm.avail_out = out_chunk_size;
275
+ strm.next_out = (unsigned char *)(gzip_data + old_gzip_data_allocd_len);
276
+ }
277
+ }
278
+ // Set output pointers
279
+ *buf_out = gzip_data;
280
+ *buflen_out = gzip_data_allocd_len - strm.avail_out;
281
+
282
+ zstream_free:
283
+ deflateEnd(&strm);
284
+ return retval;
285
+ }
@@ -0,0 +1,11 @@
1
+ #include <ruby.h>
2
+ #include "ruby_memprofiler_pprof.h"
3
+
4
+ // This should be the only symbol actually visible to Ruby
5
+ __attribute__(( visibility("default" )))
6
+ void Init_ruby_memprofiler_pprof_ext() {
7
+ mpp_rand_init();
8
+ rb_ext_ractor_safe(true);
9
+ rb_define_module("MemprofilerPprof");
10
+ mpp_setup_collector_class();
11
+ }
@@ -0,0 +1,301 @@
1
+ #ifndef __RUBY_MEMPROFILER_PPROF_H
2
+ #define __RUBY_MEMPROFILER_PPROF_H
3
+
4
+ #include <pthread.h>
5
+ #include <stdint.h>
6
+
7
+ #include <ruby.h>
8
+
9
+ // UPB header files trip up a BUNCH of -Wshorten-64-to-32
10
+ // Also ignore -Wpragmas so that if -Wshorten-64-to-32 isn't present
11
+ // (it's a clang only thing), GCC doesn't warn about the unknown warning.
12
+ #pragma GCC diagnostic push
13
+ #pragma GCC diagnostic ignored "-Wpragmas"
14
+ #pragma GCC diagnostic ignored "-Wshorten-64-to-32"
15
+ #include <upb/upb.h>
16
+ #include "pprof.upb.h"
17
+ #pragma GCC diagnostic pop
18
+
19
+ // ======== COMPAT DECLARATIONS ========
20
+
21
+ // For handling differences in ruby versions
22
+ #ifndef HAVE_RB_GC_MARK_MOVABLE
23
+ #define rb_gc_mark_movable(v) rb_gc_mark(v)
24
+ #endif
25
+
26
+ #ifndef RB_PASS_KEYWORDS
27
+ #define RB_SCAN_ARGS_LAST_HASH_KEYWORDS 3
28
+ #define rb_scan_args_kw(kw, c, v, s, ...) rb_scan_args(c, v, s, __VA_ARGS__)
29
+ #endif
30
+
31
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
32
+ #define rb_ext_ractor_safe(x) do {} while (0)
33
+ #endif
34
+
35
+ // Apparently "I just want a random number, without thinking about whether it's
36
+ // threadsafe, without thinking about whether some other part of the process needs
37
+ // the global seed to be set to some deterministic value, and without calling into
38
+ // the kernel every time" is... too much to ask for.
39
+ // BSD has arc4random(3) for this, but for glibc we have to use one of the threadsafe
40
+ // RNG's and seed a global instance of it, guarded by a mutex....
41
+ // These methods wrap all that rubbish up.
42
+ uint32_t mpp_rand();
43
+ void mpp_rand_init();
44
+
45
+
46
+ // These declarations just wrap some things from the standard library that should "always succeed", but call
47
+ // our assertion macro if they fail to abort the program.
48
+ void *mpp_xmalloc(size_t sz);
49
+ void *mpp_realloc(void *mem, size_t newsz);
50
+ void mpp_free(void *mem);
51
+ void mpp_pthread_mutex_lock(pthread_mutex_t *m);
52
+ void mpp_pthread_mutex_unlock(pthread_mutex_t *m);
53
+ int mpp_pthread_mutex_trylock(pthread_mutex_t *m);
54
+ void mpp_pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *attr);
55
+ void mpp_pthread_mutex_destroy(pthread_mutex_t *m);
56
+ void mpp_pthread_mutexattr_init(pthread_mutexattr_t *a);
57
+ void mpp_pthread_mutexattr_destroy(pthread_mutexattr_t *a);
58
+ void mpp_pthread_mutexattr_settype(pthread_mutexattr_t *a, int type);
59
+ void mpp_pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
60
+
61
+ // Need a handy assertion macro. It would be nice to re-use rb_bug for some of this, but that actually
62
+ // requires the GVL (it walks the Ruby stack frames, for one) and we (want to) run some code outside
63
+ // the GVL, so this assertion macro has to be threadsafe. So we just implement it in pretty much a
64
+ // similar way to how stdlib's assert() works (plus some stuff to prefix the gem name to the abort message
65
+ // so users know who is at fault).
66
+ #define MPP_ASSERT_STRINGIFY1(x) #x
67
+ #define MPP_ASSERT_STRINGIFY2(x) MPP_ASSERT_STRINGIFY1(x)
68
+ #define MPP_ASSERT__LINE MPP_ASSERT_STRINGIFY2(__LINE__)
69
+ __attribute__ ((noreturn))
70
+ void mpp_assert_fail(const char *msg, const char *assertion, const char *file, const char *line, const char *fn);
71
+ #define MPP_ASSERT_MSG(expr, msg) \
72
+ do { \
73
+ if ((expr) == 0) { \
74
+ mpp_assert_fail((msg), #expr, __FILE__, MPP_ASSERT__LINE, __func__); \
75
+ } \
76
+ } while (0)
77
+ #define MPP_ASSERT_FAIL(expr) MPP_ASSERT_MSG(expr, 0)
78
+
79
+ // Log a debug message to "somewhere". This could be smarter in future, but for now, this'll do.
80
+ // The implementation here does not depend on holding the GVL.
81
+ // Will automatically add a trailing newline.
82
+ void mpp_log_debug(const char *pattern, ...);
83
+
84
+ // ======== STRTAB DECLARATIONS ========
85
+
86
+ #define MPP_STRTAB_USE_STRLEN (-1)
87
+ #define MPP_STRTAB_UNKNOWN_LITERAL "(unknown)"
88
+ #define MPP_STRTAB_UNKNOWN_LITERAL_LEN ((int)strlen(MPP_STRTAB_UNKNOWN_LITERAL))
89
+
90
+ // Specialisation of the st_hash for "strings with length".
91
+ struct mpp_strtab_key {
92
+ const char *str; // Pointer to the string; n.b. it does NOT need a null-terminator
93
+ size_t str_len; // Size of the string, not including any null terminator.
94
+ };
95
+
96
+ // I copied this magic number out of st.c from Ruby.
97
+ #define FNV1_32A_INIT 0x811c9dc5
98
+
99
+ struct mpp_strtab_el {
100
+ // Pointer to null-terminated string that has been interned
101
+ char *str;
102
+ // Length of str, NOT INCLUDING the null terminator
103
+ size_t str_len;
104
+ // Number of times this string has been interned. When the refcount drops to zero, the string
105
+ // is removed from the table and str is free'd.
106
+ uint64_t refcount;
107
+ // We cleverly keep the key _inside_ the value, so we don't need a separate bunch of malloc'd
108
+ // memory for each _key_ as well as each _value_.
109
+ struct mpp_strtab_key key;
110
+ };
111
+
112
+ struct mpp_strtab {
113
+ // The actual table which contains a mapping of (string hash) -> (str_intern_tab_el *)
114
+ st_table *table;
115
+ // Number of entries in table.
116
+ int64_t table_count;
117
+ // (approximate) allocated size of the _entries_ in the st_table (but not the st_table
118
+ // itself).
119
+ size_t table_entry_size;
120
+ // Value of "" interned in the table.
121
+ const char *interned_empty_str;
122
+ };
123
+
124
+ struct mpp_strtab_index {
125
+ // The table this index is a part of and came from.
126
+ struct mpp_strtab *tab;
127
+ // The list & length of interned strings.
128
+ struct mpp_strtab_el **str_list;
129
+ int64_t str_list_len;
130
+ // This st_hash is used to convert already-interned pointers to index into str_list.
131
+ // It's a map of (uintptr_t) -> (int64_t)
132
+ st_table *pos_table;
133
+ };
134
+
135
+
136
+ // NOTE - there's better documentation of what these methods do in strtab.c itself.
137
+
138
+ // Initializes a new, empty string intern table. This will allocate memory that remains owned by the strtab
139
+ // module and saves it in tab. It also allocates memory for struct intern_tab itself.
140
+ struct mpp_strtab *mpp_strtab_new();
141
+
142
+ // Destroys a string intern table, including freeing the underlying memory used by tab, and freeing
143
+ // the memory pointed to by tab itself.
144
+ void mpp_strtab_destroy(struct mpp_strtab *tab);
145
+
146
+ // Get the size of all memory used by the table
147
+ size_t mpp_strtab_memsize(struct mpp_strtab *tab);
148
+
149
+ // Intern new strings (or increment the refcount of already-interned ones)
150
+ void mpp_strtab_intern(
151
+ struct mpp_strtab *tab, const char *str, int str_len,
152
+ const char **interned_str_out, size_t *interned_str_len_out
153
+ );
154
+ void mpp_strtab_intern_rbstr(
155
+ struct mpp_strtab *tab, VALUE rbstr,
156
+ const char **interned_str_out, size_t *interned_str_len_out
157
+ );
158
+ void mpp_strtab_intern_cstr(
159
+ struct mpp_strtab *tab, const char *str,
160
+ const char **interned_str_out, size_t *interned_str_len_out
161
+ );
162
+
163
+ // Decrement the refcount of elements in the intern table.
164
+ void mpp_strtab_release(struct mpp_strtab *tab, const char *str, size_t str_len);
165
+ void mpp_strtab_release_rbstr(struct mpp_strtab *tab, VALUE rbstr);
166
+
167
+ // Methods for building a zero=-based list of interned pointers, for building the final string table
168
+ // in the pprof protobuf.
169
+ struct mpp_strtab_index *mpp_strtab_index(struct mpp_strtab *tab);
170
+ void mpp_strtab_index_destroy(struct mpp_strtab_index *ix);
171
+ int64_t mpp_strtab_index_of(struct mpp_strtab_index *ix, const char *interned_ptr);
172
+ typedef void (*mpp_strtab_each_fn)(int64_t el_ix, const char *interned_str, size_t interned_str_len, void *ctx);
173
+ void mpp_strtab_each(struct mpp_strtab_index *ix, mpp_strtab_each_fn fn, void *ctx);
174
+
175
+ // ======== BACKTRACE DECLARATIONS ========
176
+
177
+ #define MPP_BT_METHOD_CFP 1
178
+ #define MPP_BT_METHOD_SLOWRB 2
179
+
180
+ struct mpp_rb_backtrace {
181
+ // The array of frames - most recent call FIRST.
182
+ uint64_t *frame_locations;
183
+ int64_t frames_count;
184
+ // Memory size of frames, which might actually be bigger than
185
+ // sizeof(frame_locations[0]) * frames_count
186
+ size_t memsize;
187
+ };
188
+
189
+ struct mpp_rb_loctab_function {
190
+ // Refcount
191
+ int refcount;
192
+ // Interned pointer to function name
193
+ const char *function_name;
194
+ size_t function_name_len;
195
+ // Interned pointer to file name
196
+ const char *file_name;
197
+ size_t file_name_len;
198
+ // Line number where the function starts
199
+ int64_t line_number;
200
+ // Function ID of self
201
+ uint64_t id;
202
+ };
203
+
204
+ struct mpp_rb_loctab_location {
205
+ // Refcount
206
+ int refcount;
207
+ // Function & line number. Note that we do _NOT_ hold a reference
208
+ // to the function here. Instead, each backtrace frame holds a reference
209
+ // to both the function and the location.
210
+ struct mpp_rb_loctab_function *function;
211
+ // Line number
212
+ int64_t line_number;
213
+ // Location id of self
214
+ uint64_t id;
215
+ };
216
+
217
+ struct mpp_rb_loctab {
218
+ // The table of (uint64_t location_id) -> (struct mpp_rb_loctab_location *)
219
+ st_table *locations;
220
+ int64_t location_count;
221
+ // The table of (uint64_t function_id) -> (struct mpp_rb_locatab_function *)
222
+ st_table *functions;
223
+ int64_t function_count;
224
+ // The string interning table that all the names are related to
225
+ struct mpp_strtab *strtab;
226
+ };
227
+
228
+ struct mpp_rb_loctab *mpp_rb_loctab_new(struct mpp_strtab *strtab);
229
+ void mpp_rb_loctab_destroy(struct mpp_rb_loctab *loctab);
230
+ void mpp_rb_backtrace_capture(struct mpp_rb_loctab *locatb, struct mpp_rb_backtrace **bt_out);
231
+ void mpp_rb_backtrace_capture_slowrb(struct mpp_rb_loctab *locatb, struct mpp_rb_backtrace **bt_out);
232
+ void mpp_rb_backtrace_destroy(struct mpp_rb_loctab *locatb, struct mpp_rb_backtrace *bt);
233
+ size_t mpp_rb_backtrace_memsize(struct mpp_rb_backtrace *bt);
234
+ size_t mpp_rb_loctab_memsize(struct mpp_rb_loctab *loctab);
235
+ typedef int (*mpp_rb_loctab_each_location_cb)(struct mpp_rb_loctab *loctab, struct mpp_rb_loctab_location *loc, void *ctx);
236
+ void mpp_rb_loctab_each_location(struct mpp_rb_loctab *loctab, mpp_rb_loctab_each_location_cb cb, void *ctx);
237
+ typedef int (*mpp_rb_loctab_each_function_cb)(struct mpp_rb_loctab *loctab, struct mpp_rb_loctab_function *loc, void *ctx);
238
+ void mpp_rb_loctab_each_function(struct mpp_rb_loctab *loctab, mpp_rb_loctab_each_function_cb cb, void *ctx);
239
+
240
+
241
+ // ======= MAIN DATA STRUCTURE DECLARATIONS ========
242
+ struct mpp_sample {
243
+ // The backtrace for this sample
244
+ struct mpp_rb_backtrace *bt;
245
+ // Sample has a refcount - because it's used both in the heap profiling and in the allocation profiling.
246
+ int64_t refcount;
247
+ // How big this allocation was.
248
+ size_t allocation_size;
249
+ // How big this object _currently_ is
250
+ size_t current_size;
251
+ // Weak reference to what was allocated. Validate that it's alive by consulting the live object table first.
252
+ VALUE allocated_value_weak;
253
+ // Next element in the allocation profiling sample list. DO NOT use this in the heap profiling table.
254
+ struct mpp_sample *next_alloc;
255
+ };
256
+
257
+ // ======== PROTO SERIALIZATION ROUTINES ========
258
+ struct mpp_pprof_serctx {
259
+ // Defines the allocation routine & memory arena used by this serialisation context. When the ctx
260
+ // is destroyed, we free the entire arena, so no other (protobuf) memory needs to be individually
261
+ // freed.
262
+ upb_alloc allocator;
263
+ upb_Arena *arena;
264
+ // Location table used for looking up fucntion & location IDs to strings.
265
+ struct mpp_rb_loctab *loctab;
266
+ // String intern index; recall that holding this object does _not_ require that we have exclusive
267
+ // use of the underlying string intern table, so it's safe for us to use this in a separate thread.
268
+ struct mpp_strtab_index *strindex;
269
+ // The protobuf representation we are building up.
270
+ perftools_profiles_Profile *profile_proto;
271
+
272
+ // We need to keep interned copies of some strings that will wind up in the protobuf output.
273
+ // This is so that we can put constant values like "allocations" and "count" into our pprof output
274
+ // (the pprof format requires these strings to be in the string table along with the rest of them)
275
+ const char *internstr_allocations;
276
+ const char *internstr_count;
277
+ const char *internstr_allocation_size;
278
+ const char *internstr_bytes;
279
+ const char *internstr_retained_objects;
280
+ const char *internstr_retained_size;
281
+ };
282
+
283
+ #define MPP_SAMPLE_TYPE_ALLOCATION 1
284
+ #define MPP_SAMPLE_TYPE_HEAP 2
285
+
286
+ struct mpp_pprof_serctx *mpp_pprof_serctx_new();
287
+ void mpp_pprof_serctx_destroy(struct mpp_pprof_serctx *ctx);
288
+ int mpp_pprof_serctx_set_loctab(
289
+ struct mpp_pprof_serctx *ctx, struct mpp_rb_loctab *loctab, char *errbuf, size_t errbuflen
290
+ );
291
+ int mpp_pprof_serctx_add_sample(
292
+ struct mpp_pprof_serctx *ctx, struct mpp_sample *sample, int sample_type, char *errbuf, size_t errbuflen
293
+ );
294
+ int mpp_pprof_serctx_serialize(
295
+ struct mpp_pprof_serctx *ctx, char **buf_out, size_t *buflen_out, char *errbuf, size_t errbuflen
296
+ );
297
+
298
+ // ======== COLLECTOR RUBY CLASS ========
299
+ void mpp_setup_collector_class();
300
+
301
+ #endif