ruby_memprofiler_pprof 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/ruby_memprofiler_pprof_ext/collector.c +803 -0
- data/ext/ruby_memprofiler_pprof_ext/compat.c +184 -0
- data/ext/ruby_memprofiler_pprof_ext/compile_commands.json +1 -0
- data/ext/ruby_memprofiler_pprof_ext/extconf.rb +152 -0
- data/ext/ruby_memprofiler_pprof_ext/pprof.upb.c +199 -0
- data/ext/ruby_memprofiler_pprof_ext/pprof.upb.h +924 -0
- data/ext/ruby_memprofiler_pprof_ext/pprof_out.c +430 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_hacks.c +118 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_memprofiler_pprof.c +10 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_memprofiler_pprof.h +183 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_private/ruby26/gc_private.h +324 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_private/ruby27/gc_private.h +339 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_private/ruby30/gc_private.h +361 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_private/ruby31/gc_private.h +374 -0
- data/ext/ruby_memprofiler_pprof_ext/ruby_private.h +31 -0
- data/ext/ruby_memprofiler_pprof_ext/sample.c +43 -0
- data/ext/ruby_memprofiler_pprof_ext/vendor/backtracie/backtracie.h +268 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/CONTRIBUTING.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/DESIGN.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/LICENSE +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/README.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/WORKSPACE +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/amalgamate.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/build_defs.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/lua.BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/protobuf.patch +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/py_proto_library.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/python_downloads.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/system_python.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/upb_proto_library.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/bazel/workspace_deps.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/BUILD.googleapis +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/benchmark.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/build_defs.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/compare.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/descriptor.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/descriptor_sv.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/empty.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/gen_synthetic_protos.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/benchmarks/gen_upb_binary_c.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/BUILD.bazel +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/README.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/build_defs.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/make_cmakelists.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/staleness_test.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/cmake/staleness_test_lib.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/docs/render.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/docs/style-guide.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/docs/vs-cpp-protos.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/docs/wrapping-upb.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/convert.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/convert.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor_containers.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor_containers.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor_pool.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/descriptor_pool.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/dist/BUILD.bazel +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/dist/dist.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/extension_dict.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/extension_dict.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/map.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/map.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/message.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/message.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/minimal_test.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/README.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/protobuf.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/protobuf.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/py_extension.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/python_api.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/repeated.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/repeated.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/unknown_fields.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/unknown_fields.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/python/version_script.lds +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/lunit/LICENSE +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/lunit/README.google +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/lunit/console.lua +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/lunit/lunit.lua +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/LICENSE +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/naive.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/range2-neon.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/range2-sse.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/third_party/utf8_range/utf8_range.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/BUILD.bazel +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/README.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/def.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/main.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/msg.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/test_upb.lua +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/upb.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/upb.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/upb.lua +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/bindings/lua/upbc.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/collections.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/collections.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/conformance_upb.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/conformance_upb_failures.txt +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/decode.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/decode.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/decode_fast.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/decode_fast.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/decode_internal.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/def.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/def.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/def.hpp +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/empty.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/encode.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/encode.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/fuzz/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/json_decode.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/json_decode.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/json_encode.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/json_encode.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table.hpp +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table_accessors.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table_accessors.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table_accessors_internal.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table_accessors_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/mini_table_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/msg.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/msg.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/msg_internal.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/msg_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/msg_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/port_def.inc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/port_undef.inc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/reflection.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/reflection.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/reflection.hpp +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/table.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/table_internal.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/test_cpp.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/test_cpp.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/test_generated_code.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/test_table.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/text_encode.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/text_encode.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/upb.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/upb.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/upb.hpp +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/upb_internal.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/README.md +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/compare.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/compare.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/compare_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_public_import_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/required_fields.c +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/required_fields.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/required_fields_test.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upb/util/required_fields_test.proto +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upbc/BUILD +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upbc/common.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upbc/common.h +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upbc/protoc-gen-upb.cc +0 -0
- data/ext/{ruby_memprofiler_pprof → ruby_memprofiler_pprof_ext}/vendor/upb/upbc/protoc-gen-upbdefs.cc +0 -0
- data/lib/ruby_memprofiler_pprof/atfork.rb +1 -1
- data/lib/ruby_memprofiler_pprof/block_flusher.rb +48 -4
- data/lib/ruby_memprofiler_pprof/file_flusher.rb +13 -6
- data/lib/ruby_memprofiler_pprof/profile_app.rb +8 -12
- data/lib/ruby_memprofiler_pprof/profile_data.rb +7 -8
- data/lib/ruby_memprofiler_pprof/version.rb +1 -1
- data/lib/ruby_memprofiler_pprof.rb +5 -4
- data/libexec/ruby_memprofiler_pprof_profile +6 -6
- metadata +207 -200
- data/ext/ruby_memprofiler_pprof/backtrace.c +0 -429
- data/ext/ruby_memprofiler_pprof/collector.c +0 -1055
- data/ext/ruby_memprofiler_pprof/compat.c +0 -182
- data/ext/ruby_memprofiler_pprof/extconf.rb +0 -72
- data/ext/ruby_memprofiler_pprof/pprof.upb.c +0 -170
- data/ext/ruby_memprofiler_pprof/pprof.upb.h +0 -848
- data/ext/ruby_memprofiler_pprof/pprof_out.c +0 -285
- data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +0 -11
- data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +0 -301
- data/ext/ruby_memprofiler_pprof/strtab.c +0 -391
@@ -0,0 +1,430 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/st.h>
|
3
|
+
#include <zlib.h>
|
4
|
+
|
5
|
+
#include "pprof.upb.h"
|
6
|
+
#include "ruby/st.h"
|
7
|
+
#include "ruby_memprofiler_pprof.h"
|
8
|
+
#include "upb/upb.h"
|
9
|
+
|
10
|
+
#define CHECK_IF_INTERRUPTED(action) \
|
11
|
+
do { \
|
12
|
+
uint8_t interrupted; \
|
13
|
+
__atomic_load(&ctx->interrupt, &interrupted, __ATOMIC_SEQ_CST); \
|
14
|
+
if (interrupted) { \
|
15
|
+
snprintf(errbuf, errbuflen, "interrupted"); \
|
16
|
+
action; \
|
17
|
+
} \
|
18
|
+
} while (0);
|
19
|
+
|
20
|
+
// allocator/free function for our upb_arena. Contract is:
|
21
|
+
// If "size" is 0 then the function acts like free(), otherwise it acts like
|
22
|
+
// realloc(). Only "oldsize" bytes from a previous allocation are preserved.
|
23
|
+
static void *mpp_pprof_upb_arena_malloc(upb_alloc *alloc, void *ptr, size_t oldsize, size_t size) {
|
24
|
+
if (size == 0) {
|
25
|
+
mpp_free(ptr);
|
26
|
+
return NULL;
|
27
|
+
} else {
|
28
|
+
return mpp_realloc(ptr, size);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
// Methods for a hash of (function ID, line number) -> (location)
|
33
|
+
// Needed because we have to intern a given function:line to a consistent location ID as per
|
34
|
+
// the protobuf spec.
|
35
|
+
// Key is a uint64_t[2].
|
36
|
+
static int intpair_st_hash_compare(st_data_t arg1, st_data_t arg2) {
|
37
|
+
uint64_t *k1 = (uint64_t *)arg1;
|
38
|
+
uint64_t *k2 = (uint64_t *)arg2;
|
39
|
+
|
40
|
+
if (k1[0] != k2[0]) {
|
41
|
+
return k1[0] < k2[0];
|
42
|
+
} else {
|
43
|
+
return k1[1] < k2[1];
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
// I copied this magic number out of st.c from Ruby.
|
48
|
+
#define FNV1_32A_INIT 0x811c9dc5
|
49
|
+
|
50
|
+
static st_index_t intpair_st_hash_hash(st_data_t arg) {
|
51
|
+
uint64_t *k = (uint64_t *)arg;
|
52
|
+
return st_hash(k, 2 * sizeof(uint64_t), FNV1_32A_INIT);
|
53
|
+
}
|
54
|
+
|
55
|
+
static const struct st_hash_type intpair_st_hash_type = {
|
56
|
+
.compare = intpair_st_hash_compare,
|
57
|
+
.hash = intpair_st_hash_hash,
|
58
|
+
};
|
59
|
+
|
60
|
+
// Methods for a hash of (string, len) -> (string tab index)
|
61
|
+
struct str_st_hash_key {
|
62
|
+
const char *str;
|
63
|
+
size_t str_len;
|
64
|
+
};
|
65
|
+
|
66
|
+
static int str_st_hash_compare(st_data_t arg1, st_data_t arg2) {
|
67
|
+
struct str_st_hash_key *k1 = (struct str_st_hash_key *)arg1;
|
68
|
+
struct str_st_hash_key *k2 = (struct str_st_hash_key *)arg2;
|
69
|
+
|
70
|
+
size_t smaller_len = (k1->str_len > k2->str_len) ? k2->str_len : k1->str_len;
|
71
|
+
int cmp = memcmp(k1->str, k2->str, smaller_len);
|
72
|
+
|
73
|
+
if (cmp != 0 || k1->str_len == k2->str_len) {
|
74
|
+
// Either: one of the first smaller_len bytes were different, or
|
75
|
+
// they were the same, AND the lenghts are the same, which make them the same string.
|
76
|
+
return cmp;
|
77
|
+
}
|
78
|
+
// The first smaller_len bytes are the same, but one is longer than the other.
|
79
|
+
// The shorter string should be considered smaller.
|
80
|
+
return k1->str_len > k2->str_len ? 1 : -1;
|
81
|
+
}
|
82
|
+
|
83
|
+
static st_index_t str_st_hash_hash(st_data_t arg) {
|
84
|
+
struct str_st_hash_key *k = (struct str_st_hash_key *)arg;
|
85
|
+
return st_hash(k->str, k->str_len, FNV1_32A_INIT);
|
86
|
+
}
|
87
|
+
|
88
|
+
static const struct st_hash_type str_st_hash_type = {
|
89
|
+
.compare = str_st_hash_compare,
|
90
|
+
.hash = str_st_hash_hash,
|
91
|
+
};
|
92
|
+
|
93
|
+
struct intern_string_hash_update_ctx {
|
94
|
+
struct mpp_pprof_serctx *serctx;
|
95
|
+
bool copy;
|
96
|
+
bool did_retain_out;
|
97
|
+
int index_out;
|
98
|
+
};
|
99
|
+
|
100
|
+
static int intern_string_hash_update(st_data_t *key, st_data_t *value, st_data_t arg, int existing) {
|
101
|
+
struct intern_string_hash_update_ctx *ctx = (struct intern_string_hash_update_ctx *)arg;
|
102
|
+
if (existing) {
|
103
|
+
// Value was already in the hash; just return its existing index.
|
104
|
+
ctx->index_out = *value;
|
105
|
+
} else {
|
106
|
+
struct mpp_pprof_serctx *serctx = ctx->serctx;
|
107
|
+
bool copy = ctx->copy;
|
108
|
+
upb_Arena *arena = serctx->arena;
|
109
|
+
// Value NOT already in the hash. We need to add it.
|
110
|
+
// Need to actually create a new *key; the one passed into st_update is a stack pointer, which won't be valid after
|
111
|
+
// intern_string returns.
|
112
|
+
struct str_st_hash_key *new_key = upb_Arena_Malloc(arena, sizeof(struct str_st_hash_key));
|
113
|
+
struct str_st_hash_key *old_key = (struct str_st_hash_key *)*key;
|
114
|
+
const char *old_str = old_key->str;
|
115
|
+
size_t old_str_len = old_key->str_len;
|
116
|
+
// May also need to copy the string, if it's not already a pointer to the arena.
|
117
|
+
if (copy) {
|
118
|
+
char *new_str = upb_Arena_Malloc(arena, old_str_len + 1);
|
119
|
+
memcpy(new_str, old_str, old_str_len);
|
120
|
+
new_str[old_str_len] = '\0';
|
121
|
+
new_key->str = new_str;
|
122
|
+
} else {
|
123
|
+
new_key->str = old_str;
|
124
|
+
ctx->did_retain_out = true;
|
125
|
+
}
|
126
|
+
new_key->str_len = old_str_len;
|
127
|
+
*key = (st_data_t)new_key;
|
128
|
+
|
129
|
+
// Now increment the value
|
130
|
+
*value = serctx->strings_counter++;
|
131
|
+
ctx->index_out = *value;
|
132
|
+
}
|
133
|
+
return ST_CONTINUE;
|
134
|
+
}
|
135
|
+
|
136
|
+
static int intern_string(struct mpp_pprof_serctx *serctx, const char *str, size_t len) {
|
137
|
+
struct str_st_hash_key key = {.str = str, .str_len = len};
|
138
|
+
struct intern_string_hash_update_ctx ctx = {.serctx = serctx, .index_out = 0, .copy = true};
|
139
|
+
st_update(serctx->strings, (st_data_t)&key, intern_string_hash_update, (st_data_t)&ctx);
|
140
|
+
return ctx.index_out;
|
141
|
+
}
|
142
|
+
|
143
|
+
static int intern_scratch_buffer(struct mpp_pprof_serctx *serctx) {
|
144
|
+
// If the string length is larger than the buffer capacity, clamp to capacity.
|
145
|
+
// ->scratch_buffer_capa gets set as the return value of backtracie_*_cstr, which returns the number
|
146
|
+
// of bytes that _would_ be needed to store the whole output.
|
147
|
+
size_t str_len = serctx->scratch_buffer_strlen;
|
148
|
+
if (str_len >= serctx->scratch_buffer_capa) {
|
149
|
+
str_len = serctx->scratch_buffer_capa - 1;
|
150
|
+
}
|
151
|
+
struct str_st_hash_key key = {.str = serctx->scratch_buffer, .str_len = str_len};
|
152
|
+
struct intern_string_hash_update_ctx ctx = {.serctx = serctx, .index_out = 0, .copy = false, .did_retain_out = false};
|
153
|
+
st_update(serctx->strings, (st_data_t)&key, intern_string_hash_update, (st_data_t)&ctx);
|
154
|
+
if (ctx.did_retain_out) {
|
155
|
+
serctx->scratch_buffer = NULL;
|
156
|
+
serctx->scratch_buffer_capa = 0;
|
157
|
+
serctx->scratch_buffer_strlen = 0;
|
158
|
+
}
|
159
|
+
return ctx.index_out;
|
160
|
+
}
|
161
|
+
|
162
|
+
static void ensure_scratch_buffer(struct mpp_pprof_serctx *serctx) {
|
163
|
+
if (!serctx->scratch_buffer) {
|
164
|
+
serctx->scratch_buffer = upb_Arena_Malloc(serctx->arena, 256);
|
165
|
+
serctx->scratch_buffer_capa = 256;
|
166
|
+
serctx->scratch_buffer_strlen = 0;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
// Initialize an already-allocated serialization context.
|
171
|
+
struct mpp_pprof_serctx *mpp_pprof_serctx_new(char *errbuf, size_t errbuflen) {
|
172
|
+
struct mpp_pprof_serctx *ctx = mpp_xmalloc(sizeof(struct mpp_pprof_serctx));
|
173
|
+
ctx->allocator.func = mpp_pprof_upb_arena_malloc;
|
174
|
+
ctx->arena = upb_Arena_Init(NULL, 0, &ctx->allocator);
|
175
|
+
ctx->profile_proto = perftools_profiles_Profile_new(ctx->arena);
|
176
|
+
ctx->function_pbs = st_init_numtable();
|
177
|
+
ctx->location_pbs = st_init_table(&intpair_st_hash_type);
|
178
|
+
ctx->function_ids = st_init_table(&intpair_st_hash_type);
|
179
|
+
ctx->strings = st_init_table(&str_st_hash_type);
|
180
|
+
ctx->loc_counter = 1;
|
181
|
+
ctx->function_id_counter = 1;
|
182
|
+
ctx->strings_counter = 0;
|
183
|
+
ctx->interrupt = 0;
|
184
|
+
ctx->scratch_buffer = NULL;
|
185
|
+
ctx->scratch_buffer_capa = 0;
|
186
|
+
ctx->scratch_buffer_strlen = 0;
|
187
|
+
|
188
|
+
// Pprof requires that "" be interned at position 0 in the string table, so intern that now.
|
189
|
+
intern_string(ctx, "", 0);
|
190
|
+
|
191
|
+
// Set up the sample types etc.
|
192
|
+
perftools_profiles_ValueType *retained_objects_vt =
|
193
|
+
perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
|
194
|
+
perftools_profiles_ValueType_set_type(retained_objects_vt,
|
195
|
+
intern_string(ctx, "retained_objects", strlen("retained_objects")));
|
196
|
+
perftools_profiles_ValueType_set_unit(retained_objects_vt, intern_string(ctx, "count", strlen("count")));
|
197
|
+
perftools_profiles_ValueType *retained_size_vt =
|
198
|
+
perftools_profiles_Profile_add_sample_type(ctx->profile_proto, ctx->arena);
|
199
|
+
perftools_profiles_ValueType_set_type(retained_size_vt, intern_string(ctx, "retained_size", strlen("retained_size")));
|
200
|
+
perftools_profiles_ValueType_set_unit(retained_size_vt, intern_string(ctx, "bytes", strlen("bytes")));
|
201
|
+
|
202
|
+
return ctx;
|
203
|
+
}
|
204
|
+
|
205
|
+
// Destroys the serialization context. After this call, any stringtab indexes it held
|
206
|
+
// are released, and any memory from its internal state is freed. *ctx itself is also
|
207
|
+
// freed and must not be dereferenced after this.
|
208
|
+
void mpp_pprof_serctx_destroy(struct mpp_pprof_serctx *ctx) {
|
209
|
+
if (ctx->function_pbs) {
|
210
|
+
st_free_table(ctx->function_pbs);
|
211
|
+
}
|
212
|
+
if (ctx->location_pbs) {
|
213
|
+
st_free_table(ctx->location_pbs);
|
214
|
+
}
|
215
|
+
if (ctx->function_ids) {
|
216
|
+
st_free_table(ctx->function_ids);
|
217
|
+
}
|
218
|
+
if (ctx->strings) {
|
219
|
+
st_free_table(ctx->strings);
|
220
|
+
}
|
221
|
+
upb_Arena_Free(ctx->arena);
|
222
|
+
mpp_free(ctx);
|
223
|
+
}
|
224
|
+
|
225
|
+
struct mpp_pprof_serctx_map_add_ctx {
|
226
|
+
struct mpp_pprof_serctx *ctx;
|
227
|
+
int is_error;
|
228
|
+
char *errbuf;
|
229
|
+
size_t errbuflen;
|
230
|
+
|
231
|
+
int function_name;
|
232
|
+
int file_name;
|
233
|
+
unsigned long function_id;
|
234
|
+
|
235
|
+
// for add_location
|
236
|
+
int line_number;
|
237
|
+
unsigned long location_id_out;
|
238
|
+
};
|
239
|
+
|
240
|
+
static int mpp_pprof_serctx_add_function(st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
241
|
+
if (*value) {
|
242
|
+
// already exists in the map, don't create it again.
|
243
|
+
return ST_CONTINUE;
|
244
|
+
}
|
245
|
+
|
246
|
+
struct mpp_pprof_serctx_map_add_ctx *thunkctx = (struct mpp_pprof_serctx_map_add_ctx *)data;
|
247
|
+
struct perftools_profiles_Function *fn_proto =
|
248
|
+
perftools_profiles_Profile_add_function(thunkctx->ctx->profile_proto, thunkctx->ctx->arena);
|
249
|
+
|
250
|
+
perftools_profiles_Function_set_id(fn_proto, thunkctx->function_id);
|
251
|
+
|
252
|
+
perftools_profiles_Function_set_name(fn_proto, thunkctx->function_name);
|
253
|
+
perftools_profiles_Function_set_system_name(fn_proto, thunkctx->function_name);
|
254
|
+
perftools_profiles_Function_set_filename(fn_proto, thunkctx->file_name);
|
255
|
+
|
256
|
+
*value = (st_data_t)fn_proto;
|
257
|
+
return ST_CONTINUE;
|
258
|
+
}
|
259
|
+
|
260
|
+
static int mpp_pprof_serctx_add_location(st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
261
|
+
struct mpp_pprof_serctx_map_add_ctx *thunkctx = (struct mpp_pprof_serctx_map_add_ctx *)data;
|
262
|
+
if (*value) {
|
263
|
+
// already exists in the map, don't create it again.
|
264
|
+
struct perftools_profiles_Location *existing_loc = (struct perftools_profiles_Location *)(*value);
|
265
|
+
thunkctx->location_id_out = perftools_profiles_Location_id(existing_loc);
|
266
|
+
return ST_CONTINUE;
|
267
|
+
}
|
268
|
+
|
269
|
+
struct perftools_profiles_Location *loc_proto =
|
270
|
+
perftools_profiles_Profile_add_location(thunkctx->ctx->profile_proto, thunkctx->ctx->arena);
|
271
|
+
|
272
|
+
perftools_profiles_Location_set_id(loc_proto, thunkctx->ctx->loc_counter++);
|
273
|
+
perftools_profiles_Line *line_proto = perftools_profiles_Location_add_line(loc_proto, thunkctx->ctx->arena);
|
274
|
+
perftools_profiles_Line_set_function_id(line_proto, thunkctx->function_id);
|
275
|
+
perftools_profiles_Line_set_line(line_proto, (int64_t)thunkctx->line_number);
|
276
|
+
|
277
|
+
thunkctx->location_id_out = perftools_profiles_Location_id(loc_proto);
|
278
|
+
*value = (st_data_t)loc_proto;
|
279
|
+
return ST_CONTINUE;
|
280
|
+
}
|
281
|
+
|
282
|
+
static int function_id_update_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing) {
|
283
|
+
struct mpp_pprof_serctx_map_add_ctx *thunkctx = (struct mpp_pprof_serctx_map_add_ctx *)arg;
|
284
|
+
if (!existing) {
|
285
|
+
*value = thunkctx->ctx->function_id_counter++;
|
286
|
+
}
|
287
|
+
thunkctx->function_id = *value;
|
288
|
+
return ST_CONTINUE;
|
289
|
+
}
|
290
|
+
|
291
|
+
int mpp_pprof_serctx_add_sample(struct mpp_pprof_serctx *ctx, struct mpp_sample *sample, char *errbuf,
|
292
|
+
size_t errbuflen) {
|
293
|
+
CHECK_IF_INTERRUPTED(return -1);
|
294
|
+
|
295
|
+
size_t frames_count = sample->frames_count;
|
296
|
+
perftools_profiles_Sample *sample_proto = perftools_profiles_Profile_add_sample(ctx->profile_proto, ctx->arena);
|
297
|
+
uint64_t *location_ids = perftools_profiles_Sample_resize_location_id(sample_proto, frames_count, ctx->arena);
|
298
|
+
|
299
|
+
// Protobuf needs to be in most-recent-call-first, and backtracie is also in that order.
|
300
|
+
for (size_t i = 0; i < frames_count; i++) {
|
301
|
+
// Create protobufs for function/location ID as needed.
|
302
|
+
struct mpp_pprof_serctx_map_add_ctx thunkctx;
|
303
|
+
thunkctx.ctx = ctx;
|
304
|
+
thunkctx.errbuf = errbuf;
|
305
|
+
thunkctx.errbuflen = errbuflen;
|
306
|
+
thunkctx.is_error = 0;
|
307
|
+
thunkctx.location_id_out = 0;
|
308
|
+
|
309
|
+
// Intern the frame names & filenames.
|
310
|
+
ensure_scratch_buffer(ctx);
|
311
|
+
ctx->scratch_buffer_strlen =
|
312
|
+
mpp_sample_frame_function_name(sample, i, ctx->scratch_buffer, ctx->scratch_buffer_capa);
|
313
|
+
thunkctx.function_name = intern_scratch_buffer(ctx);
|
314
|
+
|
315
|
+
ensure_scratch_buffer(ctx);
|
316
|
+
ctx->scratch_buffer_strlen = mpp_sample_frame_file_name(sample, i, ctx->scratch_buffer, ctx->scratch_buffer_capa);
|
317
|
+
thunkctx.file_name = intern_scratch_buffer(ctx);
|
318
|
+
|
319
|
+
thunkctx.line_number = mpp_sample_frame_line_number(sample, i);
|
320
|
+
|
321
|
+
// Fill in the function ID; the key is the (function_name, file_name) interned string index pair.
|
322
|
+
// This means that two frames are the same function if they have the same name and the same filename.
|
323
|
+
uint64_t func_id_key[2] = {thunkctx.function_name, thunkctx.file_name};
|
324
|
+
st_update(ctx->function_ids, (st_data_t)&func_id_key, function_id_update_func, (st_data_t)&thunkctx);
|
325
|
+
|
326
|
+
// Fill in the function & location protobuf structures.
|
327
|
+
st_update(ctx->function_pbs, thunkctx.function_id, mpp_pprof_serctx_add_function, (st_data_t)&thunkctx);
|
328
|
+
if (thunkctx.is_error) {
|
329
|
+
return -1;
|
330
|
+
}
|
331
|
+
uint64_t loc_key[2] = {thunkctx.function_id, thunkctx.line_number};
|
332
|
+
st_update(ctx->location_pbs, (st_data_t)&loc_key, mpp_pprof_serctx_add_location, (st_data_t)&thunkctx);
|
333
|
+
if (thunkctx.is_error) {
|
334
|
+
return -1;
|
335
|
+
}
|
336
|
+
MPP_ASSERT_MSG(thunkctx.location_id_out, "missing location ID out!");
|
337
|
+
location_ids[i] = thunkctx.location_id_out;
|
338
|
+
}
|
339
|
+
|
340
|
+
// Values are (retained_count, retained_size).
|
341
|
+
perftools_profiles_Sample_add_value(sample_proto, 1, ctx->arena);
|
342
|
+
perftools_profiles_Sample_add_value(sample_proto, (int64_t)sample->allocated_value_objsize, ctx->arena);
|
343
|
+
return 0;
|
344
|
+
}
|
345
|
+
|
346
|
+
static int write_each_string_table_entry(st_data_t key, st_data_t value, st_data_t arg) {
|
347
|
+
struct str_st_hash_key *string_key = (struct str_st_hash_key *)key;
|
348
|
+
upb_StringView *stringtab_list_proto = (upb_StringView *)arg;
|
349
|
+
int index = value;
|
350
|
+
stringtab_list_proto[index].data = string_key->str;
|
351
|
+
stringtab_list_proto[index].size = string_key->str_len;
|
352
|
+
return ST_CONTINUE;
|
353
|
+
}
|
354
|
+
|
355
|
+
// Serializes the contained protobuf, and gzips the result. Writes a pointer to the memory in *buf_out,
|
356
|
+
// and its length to buflen_out. The returned pointer is freed when mpp_pprof_serctx_destroy() is called,
|
357
|
+
// and should NOT be individually freed by the caller in any way (and nor is it valid after the call
|
358
|
+
// to destroy()).
|
359
|
+
int mpp_pprof_serctx_serialize(struct mpp_pprof_serctx *ctx, char **buf_out, size_t *buflen_out, char *errbuf,
|
360
|
+
size_t errbuflen) {
|
361
|
+
CHECK_IF_INTERRUPTED(return -1);
|
362
|
+
|
363
|
+
// Include the string table in the output
|
364
|
+
upb_StringView *stringtab_list_proto =
|
365
|
+
perftools_profiles_Profile_resize_string_table(ctx->profile_proto, ctx->strings_counter, ctx->arena);
|
366
|
+
st_foreach(ctx->strings, write_each_string_table_entry, (st_data_t)stringtab_list_proto);
|
367
|
+
|
368
|
+
CHECK_IF_INTERRUPTED(return -1);
|
369
|
+
|
370
|
+
// It looks like some codepaths might leak the protobuf_data pointer, but that's OK - it's in
|
371
|
+
// the ctx->arena so it'll get freed when ctx does.
|
372
|
+
size_t protobuf_data_len;
|
373
|
+
char *protobuf_data = perftools_profiles_Profile_serialize(ctx->profile_proto, ctx->arena, &protobuf_data_len);
|
374
|
+
|
375
|
+
CHECK_IF_INTERRUPTED(return -1);
|
376
|
+
|
377
|
+
// Gzip it as per standard.
|
378
|
+
z_stream strm;
|
379
|
+
int r;
|
380
|
+
int retval = 0;
|
381
|
+
|
382
|
+
strm.zalloc = Z_NULL;
|
383
|
+
strm.zfree = Z_NULL;
|
384
|
+
strm.opaque = Z_NULL;
|
385
|
+
strm.msg = NULL;
|
386
|
+
int windowBits = 15;
|
387
|
+
int GZIP_ENCODING = 16;
|
388
|
+
r = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits | GZIP_ENCODING, 8, Z_DEFAULT_STRATEGY);
|
389
|
+
if (r != Z_OK) {
|
390
|
+
ruby_snprintf(errbuf, errbuflen, "error initializing zlib (errno %d: %s)", r, strm.msg ?: "");
|
391
|
+
return -1;
|
392
|
+
}
|
393
|
+
strm.avail_in = (unsigned int)protobuf_data_len;
|
394
|
+
strm.next_in = (unsigned char *)protobuf_data;
|
395
|
+
|
396
|
+
const size_t out_chunk_size = 4096;
|
397
|
+
char *gzip_data = upb_Arena_Malloc(ctx->arena, out_chunk_size);
|
398
|
+
size_t gzip_data_allocd_len = out_chunk_size;
|
399
|
+
strm.avail_out = out_chunk_size;
|
400
|
+
strm.next_out = (unsigned char *)gzip_data;
|
401
|
+
while (true) {
|
402
|
+
CHECK_IF_INTERRUPTED(goto zstream_free);
|
403
|
+
|
404
|
+
int flush = strm.avail_in == 0 ? Z_FINISH : Z_NO_FLUSH;
|
405
|
+
r = deflate(&strm, flush);
|
406
|
+
if (r == Z_STREAM_END) {
|
407
|
+
break;
|
408
|
+
} else if (r != Z_OK) {
|
409
|
+
// uh wat?
|
410
|
+
ruby_snprintf(errbuf, errbuflen, "error doing zlib output (errno %d: %s)", r, strm.msg ?: "");
|
411
|
+
retval = -1;
|
412
|
+
goto zstream_free;
|
413
|
+
}
|
414
|
+
|
415
|
+
if (strm.avail_out == 0) {
|
416
|
+
size_t old_gzip_data_allocd_len = gzip_data_allocd_len;
|
417
|
+
gzip_data_allocd_len += out_chunk_size;
|
418
|
+
gzip_data = upb_Arena_Realloc(ctx->arena, gzip_data, old_gzip_data_allocd_len, gzip_data_allocd_len);
|
419
|
+
strm.avail_out = out_chunk_size;
|
420
|
+
strm.next_out = (unsigned char *)(gzip_data + old_gzip_data_allocd_len);
|
421
|
+
}
|
422
|
+
}
|
423
|
+
// Set output pointers
|
424
|
+
*buf_out = gzip_data;
|
425
|
+
*buflen_out = gzip_data_allocd_len - strm.avail_out;
|
426
|
+
|
427
|
+
zstream_free:
|
428
|
+
deflateEnd(&strm);
|
429
|
+
return retval;
|
430
|
+
}
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#include "ruby_private.h"
|
2
|
+
|
3
|
+
#include "ruby_memprofiler_pprof.h"
|
4
|
+
|
5
|
+
// An implementation of rb_gc_disable_no_rest(), which is defined non-static in gc.c in >= 2.7
|
6
|
+
// but not given public symbol visibility.
|
7
|
+
VALUE mpp_rb_gc_disable_no_rest() {
|
8
|
+
int old_dont_gc = GET_VM()->objspace->flags.dont_gc;
|
9
|
+
GET_VM()->objspace->flags.dont_gc = 1;
|
10
|
+
return old_dont_gc ? Qtrue : Qfalse;
|
11
|
+
}
|
12
|
+
|
13
|
+
// An implementation of rb_gc_memsize_of. Actually, in all Ruby versions >= 2.6, this has public
|
14
|
+
// symbol visibility, so just proxy through to it.
|
15
|
+
size_t mpp_rb_obj_memsize_of(VALUE obj) { return rb_obj_memsize_of(obj); }
|
16
|
+
|
17
|
+
// An implementation of is_pointer_to_heap, which is static in gc.c
|
18
|
+
static int mpp_is_pointer_to_heap(rb_objspace_t *objspace, void *ptr) {
|
19
|
+
register RVALUE *p = RANY(ptr);
|
20
|
+
register struct heap_page *page;
|
21
|
+
register size_t hi, lo, mid;
|
22
|
+
|
23
|
+
if (p < objspace->heap_pages.range[0] || p > objspace->heap_pages.range[1])
|
24
|
+
return FALSE;
|
25
|
+
if ((VALUE)p % sizeof(RVALUE) != 0)
|
26
|
+
return FALSE;
|
27
|
+
/* check if p looks like a pointer using bsearch*/
|
28
|
+
lo = 0;
|
29
|
+
hi = objspace->heap_pages.allocated_pages;
|
30
|
+
while (lo < hi) {
|
31
|
+
mid = (lo + hi) / 2;
|
32
|
+
page = objspace->heap_pages.sorted[mid];
|
33
|
+
if (page->start <= p) {
|
34
|
+
#ifdef HAVE_VARIABLE_SLOT_SIZE
|
35
|
+
// >= Ruby 3.1
|
36
|
+
if ((uintptr_t)p < ((uintptr_t)page->start + (page->total_slots * page->slot_size))) {
|
37
|
+
#else
|
38
|
+
// <= Ruby 3.0
|
39
|
+
if (p < page->start + page->total_slots) {
|
40
|
+
#endif
|
41
|
+
if (page->flags.in_tomb) {
|
42
|
+
return FALSE;
|
43
|
+
} else {
|
44
|
+
#ifdef HAVE_VARIABLE_SLOT_SIZE
|
45
|
+
if ((NUM_IN_PAGE(p) * sizeof(RVALUE)) % page->slot_size != 0)
|
46
|
+
return FALSE;
|
47
|
+
#endif
|
48
|
+
return TRUE;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
lo = mid + 1;
|
52
|
+
} else {
|
53
|
+
hi = mid;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
return FALSE;
|
57
|
+
}
|
58
|
+
|
59
|
+
// Answers the question, would rb_obj_memsize_of crash on this object?
|
60
|
+
bool mpp_is_value_still_validish(VALUE obj) {
|
61
|
+
if (obj == Qundef) {
|
62
|
+
return false;
|
63
|
+
}
|
64
|
+
if (!mpp_is_pointer_to_heap(GET_VM()->objspace, (void *)obj)) {
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
int type = RB_BUILTIN_TYPE(obj);
|
68
|
+
// do NOT return true for T_NODE; rb_obj_memsize_of() can't handle it.
|
69
|
+
switch (type) {
|
70
|
+
case T_OBJECT:
|
71
|
+
case T_MODULE:
|
72
|
+
case T_CLASS:
|
73
|
+
case T_ICLASS:
|
74
|
+
case T_STRING:
|
75
|
+
case T_ARRAY:
|
76
|
+
case T_HASH:
|
77
|
+
case T_REGEXP:
|
78
|
+
case T_DATA:
|
79
|
+
case T_MATCH:
|
80
|
+
case T_FILE:
|
81
|
+
case T_RATIONAL:
|
82
|
+
case T_COMPLEX:
|
83
|
+
case T_IMEMO:
|
84
|
+
case T_FLOAT:
|
85
|
+
case T_SYMBOL:
|
86
|
+
case T_BIGNUM:
|
87
|
+
case T_STRUCT:
|
88
|
+
return true;
|
89
|
+
}
|
90
|
+
return false;
|
91
|
+
}
|
92
|
+
|
93
|
+
// Peeks into internal GVL structures to spy if someone else is waiting for the GVL; we can
|
94
|
+
// then be polite and yield it for them.
|
95
|
+
bool mpp_is_someone_else_waiting_for_gvl() {
|
96
|
+
rb_global_vm_lock_t *gvl;
|
97
|
+
#ifdef HAVE_GET_RACTOR
|
98
|
+
gvl = &(GET_RACTOR()->threads.gvl);
|
99
|
+
#else
|
100
|
+
gvl = &(GET_VM()->gvl);
|
101
|
+
#endif
|
102
|
+
pthread_mutex_lock(&gvl->lock);
|
103
|
+
bool someone_waiting = !list_empty(&gvl->waitq);
|
104
|
+
pthread_mutex_unlock(&gvl->lock);
|
105
|
+
return someone_waiting;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Unfreezes a passed in object so we can force setting something on
|
109
|
+
// its internal attributes hash.
|
110
|
+
VALUE mpp_rb_ivar_set_ignore_frozen(VALUE obj, ID key, VALUE value) {
|
111
|
+
bool was_frozen = RB_OBJ_FROZEN(obj);
|
112
|
+
RB_FL_UNSET_RAW(obj, FL_FREEZE);
|
113
|
+
VALUE ret = rb_ivar_set(obj, key, value);
|
114
|
+
if (was_frozen) {
|
115
|
+
RB_FL_SET_RAW(obj, FL_FREEZE);
|
116
|
+
}
|
117
|
+
return ret;
|
118
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#include "ruby_memprofiler_pprof.h"
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
// This should be the only symbol actually visible to Ruby
|
5
|
+
__attribute__((visibility("default"))) void Init_ruby_memprofiler_pprof_ext() {
|
6
|
+
rb_ext_ractor_safe(true);
|
7
|
+
|
8
|
+
rb_define_module("MemprofilerPprof");
|
9
|
+
mpp_setup_collector_class();
|
10
|
+
}
|