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.
- checksums.yaml +7 -0
- data/ext/ruby_memprofiler_pprof/backtrace.c +429 -0
- data/ext/ruby_memprofiler_pprof/collector.c +1055 -0
- data/ext/ruby_memprofiler_pprof/compat.c +182 -0
- data/ext/ruby_memprofiler_pprof/extconf.rb +72 -0
- data/ext/ruby_memprofiler_pprof/pprof.upb.c +170 -0
- data/ext/ruby_memprofiler_pprof/pprof.upb.h +848 -0
- data/ext/ruby_memprofiler_pprof/pprof_out.c +285 -0
- data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +11 -0
- data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +301 -0
- data/ext/ruby_memprofiler_pprof/strtab.c +391 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/BUILD +719 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/CONTRIBUTING.md +37 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/DESIGN.md +201 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/LICENSE +26 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/README.md +78 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/WORKSPACE +58 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/BUILD +53 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/amalgamate.py +129 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/build_defs.bzl +160 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/lua.BUILD +127 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/protobuf.patch +54 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/py_proto_library.bzl +137 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/python_downloads.bzl +84 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/system_python.bzl +101 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/upb_proto_library.bzl +388 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/workspace_deps.bzl +89 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD +252 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD.googleapis +54 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/benchmark.cc +333 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/build_defs.bzl +88 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/compare.py +118 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor.proto +888 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor_sv.proto +890 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/empty.proto +6 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +64 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_synthetic_protos.py +118 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_upb_binary_c.py +65 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/BUILD.bazel +102 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/README.md +23 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/build_defs.bzl +73 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/make_cmakelists.py +340 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test.py +57 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test_lib.py +186 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/docs/render.py +43 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/docs/style-guide.md +65 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/docs/vs-cpp-protos.md +255 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/docs/wrapping-upb.md +444 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/BUILD +216 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.c +394 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.h +63 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.c +1694 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.h +80 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.c +704 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.h +114 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.c +650 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.h +48 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/BUILD.bazel +193 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/dist.bzl +190 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.c +247 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.h +39 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.c +522 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.h +66 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.c +1909 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.h +101 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/minimal_test.py +183 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/BUILD +70 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/README.md +11 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +45 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +46 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +37 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +52 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +32 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +36 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +45 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +36 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +30 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.c +350 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.h +230 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/py_extension.bzl +55 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/python_api.h +61 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.c +828 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.h +69 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.c +404 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.h +39 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/python/version_script.lds +6 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/LICENSE +32 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/README.google +9 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/console.lua +156 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/lunit.lua +725 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/BUILD +19 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/LICENSE +21 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/naive.c +92 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-neon.c +157 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-sse.c +170 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/utf8_range.h +9 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/BUILD.bazel +129 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/README.md +8 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/def.c +939 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +138 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/main.c +83 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/msg.c +1118 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test.proto +69 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test_upb.lua +846 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.c +258 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.h +132 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.lua +58 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upbc.cc +134 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.c +192 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.h +174 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb.c +346 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb_failures.txt +1 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.c +1221 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.h +94 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.c +1055 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.h +153 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_internal.h +211 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.c +3262 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.h +414 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.hpp +438 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/empty.proto +1 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.c +604 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.h +71 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/BUILD +13 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +43 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.c +1509 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.h +47 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.c +776 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.h +62 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.c +1147 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.h +189 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.hpp +112 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.c +363 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.h +263 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_internal.h +59 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_test.cc +425 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_test.cc +230 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.c +428 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.h +114 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_internal.h +836 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.cc +491 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.proto +195 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_def.inc +261 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_undef.inc +62 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.c +323 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.h +109 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.hpp +37 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table.c +926 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table_internal.h +385 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test.proto +74 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.cc +186 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.proto +12 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_generated_code.cc +977 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_table.cc +580 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.c +472 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.h +64 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.c +362 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.h +378 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.hpp +115 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb_internal.h +68 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/BUILD +121 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/README.md +7 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.c +300 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.h +66 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare_test.cc +236 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.c +572 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.h +62 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_public_import_test.proto +32 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +36 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.cc +143 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.proto +119 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +28 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +28 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.c +311 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.h +94 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.cc +202 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.proto +48 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/BUILD +78 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.cc +77 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.h +112 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upb.cc +1997 -0
- data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upbdefs.cc +193 -0
- data/lib/ruby_memprofiler_pprof/atfork.rb +77 -0
- data/lib/ruby_memprofiler_pprof/block_flusher.rb +61 -0
- data/lib/ruby_memprofiler_pprof/file_flusher.rb +45 -0
- data/lib/ruby_memprofiler_pprof/profile_app.rb +30 -0
- data/lib/ruby_memprofiler_pprof/profile_data.rb +18 -0
- data/lib/ruby_memprofiler_pprof/version.rb +5 -0
- data/lib/ruby_memprofiler_pprof.rb +8 -0
- data/libexec/ruby_memprofiler_pprof_profile +16 -0
- 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
|