ruby_memprofiler_pprof 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|