ruby_memprofiler_pprof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +7 -0
  2. data/ext/ruby_memprofiler_pprof/backtrace.c +429 -0
  3. data/ext/ruby_memprofiler_pprof/collector.c +1055 -0
  4. data/ext/ruby_memprofiler_pprof/compat.c +182 -0
  5. data/ext/ruby_memprofiler_pprof/extconf.rb +72 -0
  6. data/ext/ruby_memprofiler_pprof/pprof.upb.c +170 -0
  7. data/ext/ruby_memprofiler_pprof/pprof.upb.h +848 -0
  8. data/ext/ruby_memprofiler_pprof/pprof_out.c +285 -0
  9. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +11 -0
  10. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +301 -0
  11. data/ext/ruby_memprofiler_pprof/strtab.c +391 -0
  12. data/ext/ruby_memprofiler_pprof/vendor/upb/BUILD +719 -0
  13. data/ext/ruby_memprofiler_pprof/vendor/upb/CONTRIBUTING.md +37 -0
  14. data/ext/ruby_memprofiler_pprof/vendor/upb/DESIGN.md +201 -0
  15. data/ext/ruby_memprofiler_pprof/vendor/upb/LICENSE +26 -0
  16. data/ext/ruby_memprofiler_pprof/vendor/upb/README.md +78 -0
  17. data/ext/ruby_memprofiler_pprof/vendor/upb/WORKSPACE +58 -0
  18. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/BUILD +53 -0
  19. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/amalgamate.py +129 -0
  20. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/build_defs.bzl +160 -0
  21. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/lua.BUILD +127 -0
  22. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/protobuf.patch +54 -0
  23. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/py_proto_library.bzl +137 -0
  24. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/python_downloads.bzl +84 -0
  25. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/system_python.bzl +101 -0
  26. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/upb_proto_library.bzl +388 -0
  27. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/workspace_deps.bzl +89 -0
  28. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD +252 -0
  29. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD.googleapis +54 -0
  30. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/benchmark.cc +333 -0
  31. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/build_defs.bzl +88 -0
  32. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/compare.py +118 -0
  33. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor.proto +888 -0
  34. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor_sv.proto +890 -0
  35. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/empty.proto +6 -0
  36. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +64 -0
  37. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_synthetic_protos.py +118 -0
  38. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_upb_binary_c.py +65 -0
  39. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/BUILD.bazel +102 -0
  40. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/README.md +23 -0
  41. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/build_defs.bzl +73 -0
  42. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/make_cmakelists.py +340 -0
  43. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test.py +57 -0
  44. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test_lib.py +186 -0
  45. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/render.py +43 -0
  46. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/style-guide.md +65 -0
  47. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/vs-cpp-protos.md +255 -0
  48. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/wrapping-upb.md +444 -0
  49. data/ext/ruby_memprofiler_pprof/vendor/upb/python/BUILD +216 -0
  50. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.c +394 -0
  51. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.h +63 -0
  52. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.c +1694 -0
  53. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.h +80 -0
  54. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.c +704 -0
  55. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.h +114 -0
  56. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.c +650 -0
  57. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.h +48 -0
  58. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/BUILD.bazel +193 -0
  59. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/dist.bzl +190 -0
  60. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.c +247 -0
  61. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.h +39 -0
  62. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.c +522 -0
  63. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.h +66 -0
  64. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.c +1909 -0
  65. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.h +101 -0
  66. data/ext/ruby_memprofiler_pprof/vendor/upb/python/minimal_test.py +183 -0
  67. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/BUILD +70 -0
  68. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/README.md +11 -0
  69. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +30 -0
  70. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +45 -0
  71. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +46 -0
  72. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +30 -0
  73. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +30 -0
  74. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +30 -0
  75. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +37 -0
  76. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +52 -0
  77. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +32 -0
  78. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +36 -0
  79. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +45 -0
  80. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +30 -0
  81. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +30 -0
  82. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +30 -0
  83. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +30 -0
  84. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +30 -0
  85. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +36 -0
  86. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +30 -0
  87. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.c +350 -0
  88. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.h +230 -0
  89. data/ext/ruby_memprofiler_pprof/vendor/upb/python/py_extension.bzl +55 -0
  90. data/ext/ruby_memprofiler_pprof/vendor/upb/python/python_api.h +61 -0
  91. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.c +828 -0
  92. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.h +69 -0
  93. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.c +404 -0
  94. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.h +39 -0
  95. data/ext/ruby_memprofiler_pprof/vendor/upb/python/version_script.lds +6 -0
  96. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/LICENSE +32 -0
  97. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/README.google +9 -0
  98. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/console.lua +156 -0
  99. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/lunit.lua +725 -0
  100. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/BUILD +19 -0
  101. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/LICENSE +21 -0
  102. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/naive.c +92 -0
  103. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-neon.c +157 -0
  104. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-sse.c +170 -0
  105. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/utf8_range.h +9 -0
  106. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/BUILD.bazel +129 -0
  107. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/README.md +8 -0
  108. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/def.c +939 -0
  109. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +138 -0
  110. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/main.c +83 -0
  111. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/msg.c +1118 -0
  112. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test.proto +69 -0
  113. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test_upb.lua +846 -0
  114. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.c +258 -0
  115. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.h +132 -0
  116. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.lua +58 -0
  117. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upbc.cc +134 -0
  118. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.c +192 -0
  119. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.h +174 -0
  120. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb.c +346 -0
  121. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb_failures.txt +1 -0
  122. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.c +1221 -0
  123. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.h +94 -0
  124. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.c +1055 -0
  125. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.h +153 -0
  126. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_internal.h +211 -0
  127. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.c +3262 -0
  128. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.h +414 -0
  129. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.hpp +438 -0
  130. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/empty.proto +1 -0
  131. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.c +604 -0
  132. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.h +71 -0
  133. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/BUILD +13 -0
  134. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +43 -0
  135. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.c +1509 -0
  136. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.h +47 -0
  137. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.c +776 -0
  138. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.h +62 -0
  139. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.c +1147 -0
  140. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.h +189 -0
  141. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.hpp +112 -0
  142. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.c +363 -0
  143. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.h +263 -0
  144. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_internal.h +59 -0
  145. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_test.cc +425 -0
  146. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_test.cc +230 -0
  147. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.c +428 -0
  148. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.h +114 -0
  149. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_internal.h +836 -0
  150. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.cc +491 -0
  151. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.proto +195 -0
  152. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_def.inc +261 -0
  153. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_undef.inc +62 -0
  154. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.c +323 -0
  155. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.h +109 -0
  156. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.hpp +37 -0
  157. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table.c +926 -0
  158. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table_internal.h +385 -0
  159. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test.proto +74 -0
  160. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.cc +186 -0
  161. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.proto +12 -0
  162. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_generated_code.cc +977 -0
  163. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_table.cc +580 -0
  164. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.c +472 -0
  165. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.h +64 -0
  166. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.c +362 -0
  167. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.h +378 -0
  168. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.hpp +115 -0
  169. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb_internal.h +68 -0
  170. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/BUILD +121 -0
  171. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/README.md +7 -0
  172. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.c +300 -0
  173. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.h +66 -0
  174. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare_test.cc +236 -0
  175. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.c +572 -0
  176. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.h +62 -0
  177. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_public_import_test.proto +32 -0
  178. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +36 -0
  179. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.cc +143 -0
  180. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.proto +119 -0
  181. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +28 -0
  182. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +28 -0
  183. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.c +311 -0
  184. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.h +94 -0
  185. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.cc +202 -0
  186. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.proto +48 -0
  187. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/BUILD +78 -0
  188. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.cc +77 -0
  189. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.h +112 -0
  190. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upb.cc +1997 -0
  191. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upbdefs.cc +193 -0
  192. data/lib/ruby_memprofiler_pprof/atfork.rb +77 -0
  193. data/lib/ruby_memprofiler_pprof/block_flusher.rb +61 -0
  194. data/lib/ruby_memprofiler_pprof/file_flusher.rb +45 -0
  195. data/lib/ruby_memprofiler_pprof/profile_app.rb +30 -0
  196. data/lib/ruby_memprofiler_pprof/profile_data.rb +18 -0
  197. data/lib/ruby_memprofiler_pprof/version.rb +5 -0
  198. data/lib/ruby_memprofiler_pprof.rb +8 -0
  199. data/libexec/ruby_memprofiler_pprof_profile +16 -0
  200. metadata +257 -0
@@ -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