diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 79cbc290b..000000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: CI
-
-on:
- push:
- branches: [ "master" ]
- pull_request:
- branches: [ "master" ]
-
- # Allows you to run this workflow manually from the Actions tab
- workflow_dispatch:
-
-jobs:
- build-amd64:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
- - run: ./build.sh -m amd64
-
- build-alpine:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
- - run: ./build.sh -m alpine
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 939e5341e..977af8bb8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,28 +1 @@
-# How to Contribute
-
-We'd love to accept your patches and contributions to this project. There are
-just a few small guidelines you need to follow.
-
-## Contributor License Agreement
-
-Contributions to this project must be accompanied by a Contributor License
-Agreement. You (or your employer) retain the copyright to your contribution;
-this simply gives us permission to use and redistribute your contributions as
-part of the project. Head over to to see
-your current agreements on file or to sign a new one.
-
-You generally only need to submit a CLA once, so if you've already submitted one
-(even if it was for a different project), you probably don't need to do it
-again.
-
-## Code reviews
-
-All submissions, including submissions by project members, require review. We
-use GitHub pull requests for this purpose. Consult
-[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
-information on using pull requests.
-
-## Community Guidelines
-
-This project follows [Google's Open Source Community
-Guidelines](https://opensource.google.com/conduct/).
+This repo cannot currently accept open source contributions.
diff --git a/Dockerfile b/Dockerfile
index 50c6af32a..138a8c453 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -61,6 +61,7 @@ RUN git clone --depth=1 -b curl-7_69_1 https://github.com/curl/curl.git /tmp/cur
./buildconf && \
./configure --disable-ldap --disable-shared --without-libssh2 \
--without-librtmp --without-libidn --enable-static \
+ --without-libidn2 \
--with-pic --with-ssl=/usr/local/ssl/ && \
make -j && make install && \
cd ~ && rm -rf /tmp/curl
@@ -86,13 +87,15 @@ RUN mkdir /tmp/glog && cd /tmp/glog && \
# process of gRPC puts the OpenSSL static object files into the gRPC archive
# which causes link errors later when the agent is linked with the static
# OpenSSL library itself.
+# Limit the number of threads used by make, as unlimited threads causes
+# memory exhausted error on the Kokoro VM.
RUN git clone --depth=1 --recursive -b v1.28.1 https://github.com/grpc/grpc.git /tmp/grpc && \
cd /tmp/grpc && \
cd third_party/protobuf && \
./autogen.sh && \
./configure --with-pic CXXFLAGS="$(pkg-config --cflags protobuf)" LIBS="$(pkg-config --libs protobuf)" LDFLAGS="-Wl,--no-as-needed" && \
- make -j && make install && ldconfig && \
+ make -j4 && make install && ldconfig && \
cd ../.. && \
- CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make -j CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 && \
+ CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make -j4 CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 && \
CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 install && \
rm -rf /tmp/grpc
diff --git a/Dockerfile.alpine b/Dockerfile.alpine
index b4922a962..202537a91 100644
--- a/Dockerfile.alpine
+++ b/Dockerfile.alpine
@@ -59,6 +59,7 @@ RUN git clone --depth=1 -b curl-7_69_1 https://github.com/curl/curl.git /tmp/cur
./buildconf && \
./configure --disable-ldap --disable-shared --without-libssh2 \
--without-librtmp --without-libidn --enable-static \
+ --without-libidn2 \
--with-pic --with-ssl=/usr/local/ssl/ && \
make -j && make install && \
cd ~ && rm -rf /tmp/curl
@@ -85,13 +86,15 @@ RUN mkdir /tmp/glog && cd /tmp/glog && \
# process of gRPC puts the OpenSSL static object files into the gRPC archive
# which causes link errors later when the agent is linked with the static
# OpenSSL library itself.
+# Limit the number of threads used by make, as unlimited threads causes
+# memory exhausted error on the Kokoro VM.
RUN git clone --depth=1 --recursive -b v1.28.1 https://github.com/grpc/grpc.git /tmp/grpc && \
cd /tmp/grpc && \
cd third_party/protobuf && \
./autogen.sh && \
./configure --with-pic CXXFLAGS="$(pkg-config --cflags protobuf)" LIBS="$(pkg-config --libs protobuf)" LDFLAGS="-Wl,--no-as-needed" && \
- make -j && make install && ldconfig / && \
+ make -j4 && make install && ldconfig / && \
cd ../.. && \
- CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make -j CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 && \
+ CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make -j4 CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 && \
CPPFLAGS="-I /usr/local/ssl/include" LDFLAGS="-L /usr/local/ssl/lib/ -Wl,--no-as-needed" make CONFIG=opt EMBED_OPENSSL=false V=1 HAS_SYSTEM_OPENSSL_NPN=0 install && \
rm -rf /tmp/grpc
diff --git a/Makefile b/Makefile
index ce3b49955..15b6e6d33 100644
--- a/Makefile
+++ b/Makefile
@@ -82,6 +82,7 @@ PROFILER_API_SOURCES = \
$(GENFILES_PATH)/google/api/annotations.pb.cc \
$(GENFILES_PATH)/google/api/client.pb.cc \
$(GENFILES_PATH)/google/api/http.pb.cc \
+ $(GENFILES_PATH)/google/api/launch_stage.pb.cc \
$(GENFILES_PATH)/google/devtools/cloudprofiler/v2/profiler.grpc.pb.cc \
$(GENFILES_PATH)/google/devtools/cloudprofiler/v2/profiler.pb.cc \
$(GENFILES_PATH)/google/protobuf/duration.pb.cc \
@@ -231,6 +232,10 @@ $(GENFILES_PATH)/%annotations.pb.h $(GENFILES_PATH)/%annotations.pb.cc : third_p
mkdir -p $(dir $@)
$(PROTOC) -Ithird_party/googleapis -I$(PROTOBUF_INCLUDE_PATH) --cpp_out=$(GENFILES_PATH) $<
+$(GENFILES_PATH)/%launch_stage.pb.h $(GENFILES_PATH)/%launch_stage.pb.cc : third_party/googleapis/%launch_stage.proto
+ mkdir -p $(dir $@)
+ $(PROTOC) -Ithird_party/googleapis -I$(PROTOBUF_INCLUDE_PATH) --cpp_out=$(GENFILES_PATH) $<
+
$(GENFILES_PATH)/%client.pb.h $(GENFILES_PATH)/%client.pb.cc : third_party/googleapis/%client.proto
mkdir -p $(dir $@)
$(PROTOC) -Ithird_party/googleapis -I$(PROTOBUF_INCLUDE_PATH) --cpp_out=$(GENFILES_PATH) $<
diff --git a/build.sh b/build.sh
index ec5ccbd9c..97099397f 100755
--- a/build.sh
+++ b/build.sh
@@ -38,7 +38,7 @@ while getopts ":d:m:v:" opt; do
m)
TARGET=$OPTARG
if [[ "${TARGET}" == "arm64" ]]; then
- if [[ "${MACHINE_TYPE}" != "aarch64" ]] || [[ "${MACHINE_TYPE}" != "arm64" ]]; then
+ if [[ "${MACHINE_TYPE}" != "aarch64" ]] && [[ "${MACHINE_TYPE}" != "arm64" ]]; then
echo "-m arm64 is supported only when running on an ARM64 system."
exit;
fi
diff --git a/src/entry.cc b/src/entry.cc
index 24c20fd6f..3d0d17dcd 100644
--- a/src/entry.cc
+++ b/src/entry.cc
@@ -100,7 +100,7 @@ void CreateJMethodIDsForClass(jvmtiEnv *jvmti, jclass klass) {
// JVMTI_ERROR_CLASS_NOT_PREPARED is okay because some classes may
// be loaded but not prepared at this point.
google::javaprofiler::JvmtiScopedPtr ksig(jvmti);
- JVMTI_ERROR((jvmti->GetClassSignature(klass, ksig.GetRef(), NULL)));
+ JVMTI_ERROR((jvmti->GetClassSignature(klass, ksig.GetRef(), nullptr)));
LOG(ERROR) << "Failed to create method IDs for methods in class "
<< ksig.Get() << " with error " << e;
}
@@ -122,8 +122,11 @@ void JNICALL OnVMInit(jvmtiEnv *jvmti, JNIEnv *jni_env, jthread thread) {
}
if (FLAGS_cprof_enable_heap_sampling) {
+ // TODO: Allow using the JVM's stack tracer with a flag once
+ // we can get the current context in a cloud build.
google::javaprofiler::HeapMonitor::Enable(
- jvmti, jni_env, FLAGS_cprof_heap_sampling_interval);
+ jvmti, jni_env, FLAGS_cprof_heap_sampling_interval,
+ false /* use_jvm_trace */);
}
worker->Start(jni_env);
@@ -146,7 +149,7 @@ void JNICALL OnVMDeath(jvmtiEnv *jvmti_env, JNIEnv *jni_env) {
LOG(INFO) << "On VM death";
worker->Stop();
delete worker;
- worker = NULL;
+ worker = nullptr;
if (google::javaprofiler::HeapMonitor::Enabled()) {
google::javaprofiler::HeapMonitor::Disable();
@@ -231,7 +234,7 @@ static bool RegisterJvmti(jvmtiEnv *jvmti) {
// Events are enumerated in jvmstatagent.h
for (int i = 0; i < events.size(); i++) {
JVMTI_ERROR_1(
- (jvmti->SetEventNotificationMode(JVMTI_ENABLE, events[i], NULL)),
+ (jvmti->SetEventNotificationMode(JVMTI_ENABLE, events[i], nullptr)),
false);
}
diff --git a/src/pem_roots.cc b/src/pem_roots.cc
index 7a3cf8711..5512b5b3c 100644
--- a/src/pem_roots.cc
+++ b/src/pem_roots.cc
@@ -806,152 +806,6 @@ dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
ReYNnyicsbkqWletNw+vHX/bvZ8=
-----END CERTIFICATE-----
-# Operating CA: Google Trust Services LLC
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4
-# Label: "GlobalSign ECC Root CA - R4"
-# Serial: 14367148294922964480859022125800977897474
-# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e
-# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb
-# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c
------BEGIN CERTIFICATE-----
-MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
-FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
-uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
-kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
-ewv4n4Q=
------END CERTIFICATE-----
-
-# Operating CA: Google Trust Services LLC
-# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1
-# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1
-# Label: "GTS Root R1"
-# Serial: 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1
-# MD5 Fingerprint: 82:1A:EF:D4:D2:4A:F2:9F:E2:3D:97:06:14:70:72:85
-# SHA1 Fingerprint: E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8
-# SHA256 Fingerprint: 2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:D3:CC:19:6B:F0:9A:54:72
------BEGIN CERTIFICATE-----
-MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
-MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
-QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
-MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
-cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
-f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
-mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
-zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
-fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
-vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
-Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
-zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
-Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
-k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
-DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
-lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
-Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
-d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
-XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
-gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
-d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
-J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
-DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
-+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
-F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
-SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
-E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
------END CERTIFICATE-----
-
-# Operating CA: Google Trust Services LLC
-# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2
-# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R2
-# Label: "GTS Root R2"
-# Serial: 6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f
-# MD5 Fingerprint: 44:ED:9A:0E:A4:09:3B:00:F2:AE:4C:A3:C6:61:B0:8B
-# SHA1 Fingerprint: D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D
-# SHA256 Fingerprint: C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:EA:4E:64:55:D7:58:5C:60
------BEGIN CERTIFICATE-----
-MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
-MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
-QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
-MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
-cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
-CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
-GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
-XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
-re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
-PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
-mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
-8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
-x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
-nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
-kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
-twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
-8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
-vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
-z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
-pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
-pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
-R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
-RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
-0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
-5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
-izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
-yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
------END CERTIFICATE-----
-
-# Operating CA: Google Trust Services LLC
-# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3
-# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R3
-# Label: "GTS Root R3"
-# Serial: 6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d
-# MD5 Fingerprint: 1A:79:5B:6B:04:52:9C:5D:C7:74:33:1B:25:9A:F9:25
-# SHA1 Fingerprint: 30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5
-# SHA256 Fingerprint: 15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:4E:1E:6B:7A:71:BA:BC:E5
------BEGIN CERTIFICATE-----
-MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
-CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
-MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
-MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
-Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
-736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
-DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
-DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
-fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
-njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
------END CERTIFICATE-----
-
-# Operating CA: Google Trust Services LLC
-# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4
-# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R4
-# Label: "GTS Root R4"
-# Serial: 6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99
-# MD5 Fingerprint: 5D:B6:6A:C4:60:17:24:6A:1A:99:A8:4B:EE:5E:B4:26
-# SHA1 Fingerprint: 2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB
-# SHA256 Fingerprint: 71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:EA:4D:CA:7F:C9:51:A4:BD
------BEGIN CERTIFICATE-----
-MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
-CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
-MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
-MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
-Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
-hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
-xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
-DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
-CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
-sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
------END CERTIFICATE-----
-
# Operating CA: Sectigo
# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
# Subject: CN=AAA Certificate Services O=Comodo CA Limited
@@ -1155,6 +1009,151 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
+
+# Operating CA: Google Trust Services LLC
+# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R1
+# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1
+# Label: "GTS Root R1"
+# Serial: 0203E5936F31B01349886BA217
+# MD5 Fingerprint: 05:FE:D0:BF:71:A8:A3:76:63:DA:01:E0:D8:52:DC:40
+# SHA1 Fingerprint: E5:8C:1C:C4:91:3B:38:63:4B:E9:10:6E:E3:AD:8E:6B:9D:D9:81:4A
+# SHA256 Fingerprint: D9:47:43:2A:BD:E7:B7:FA:90:FC:2E:6B:59:10:1B:12:80:E0:E1:C7:E4:E4:0F:A3:C6:88:7F:FF:57:A7:F4:CF
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
+27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
+Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
+TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
+qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
+szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
+Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
+MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
+wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
+aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
+VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
+C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
+QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
+h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
+7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
+ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
+MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
+Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
+6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
+0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
+2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
+bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
+-----END CERTIFICATE-----
+
+# Operating CA: Google Trust Services LLC
+# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R2
+# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R2
+# Label: "GTS Root R2"
+# Serial: 0203E5AEC58D04251AAB1125AA
+# MD5 Fingerprint=1E:39:C0:53:E6:1E:29:82:0B:CA:52:55:36:5D:57:DC
+# SHA1 Fingerprint=9A:44:49:76:32:DB:DE:FA:D0:BC:FB:5A:7B:17:BD:9E:56:09:24:94
+# SHA256 Fingerprint=8D:25:CD:97:22:9D:BF:70:35:6B:DA:4E:B3:CC:73:40:31:E2:4C:F0:0F:AF:CF:D3:2D:C7:6E:B5:84:1C:7E:A8
+-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt
+nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY
+6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu
+MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k
+RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg
+f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV
++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo
+dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
+Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa
+G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq
+gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H
+vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
+0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC
+B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u
+NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg
+yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev
+HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6
+xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR
+TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg
+JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
+7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl
+6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL
+-----END CERTIFICATE-----
+
+# Operating CA: Google Trust Services LLC
+# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R3
+# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R3
+# Label: "GTS Root R3"
+# Serial: 0203E5B882EB20F825276D3D66
+# MD5 Fingerprint: 3E:E7:9D:58:02:94:46:51:94:E5:E0:22:4A:8B:E7:73
+# SHA1 Fingerprint: ED:E5:71:80:2B:C8:92:B9:5B:83:3C:D2:32:68:3F:09:CD:A0:1E:46
+# SHA256 Fingerprint: 34:D8:A7:3E:E2:08:D9:BC:DB:0D:95:65:20:93:4B:4E:40:E6:94:82:59:6E:8B:6F:73:C8:42:6B:01:0A:6F:48
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G
+jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2
+4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7
+VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm
+ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
+-----END CERTIFICATE-----
+
+# Operating CA: Google Trust Services LLC
+# Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R4
+# Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R4
+# Label: "GTS Root R4"
+# Serial: 0203E5C068EF631A9C72905052
+# MD5 Fingerprint=43:96:83:77:19:4D:76:B3:9D:65:52:E4:1D:22:A5:E8
+# SHA1 Fingerprint=77:D3:03:67:B5:E0:0C:15:F6:0C:38:61:DF:7C:E1:3B:92:46:4D:47
+# SHA256 Fingerprint=34:9D:FA:40:58:C5:E2:63:12:3B:39:8A:E7:95:57:3C:4E:13:13:C8:3F:E6:8F:93:55:6C:D5:E8:03:1B:3C:7D
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
+VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
+A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
+WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
+IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi
+QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR
+HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D
+9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8
+p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
+-----END CERTIFICATE-----
+
+# Operating CA: Google Trust Services LLC
+# Subject: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
+# Issuer: OU = GlobalSign ECC Root CA - R4, O = GlobalSign, CN = GlobalSign
+# Label: "GlobalSign R4"
+# Serial: 0203E57EF53F93FDA50921B2A6
+# MD5 Fingerprint: 26:29:F8:6D:E1:88:BF:A2:65:7F:AA:C4:CD:0F:7F:FC
+# SHA1 Fingerprint: 6B:A0:B0:98:E1:71:EF:5A:AD:FE:48:15:80:77:10:F4:BD:6F:0B:28
+# SHA256 Fingerprint: B0:85:D7:0B:96:4F:19:1A:73:E4:AF:0D:54:AE:7A:0E:07:AA:FD:AF:9B:71:DD:08:62:13:8A:B7:32:5A:24:A2
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
+VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
+bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
+MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g
+UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx
+uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV
+HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/
++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147
+bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
+-----END CERTIFICATE-----
)|"; // end kPemRootCerts
} // namespace profiler
diff --git a/src/profiler.cc b/src/profiler.cc
index 2cc1bbf9f..69cbe791f 100644
--- a/src/profiler.cc
+++ b/src/profiler.cc
@@ -158,7 +158,7 @@ bool SignalHandler::SetSigprofInterval(int64_t period_usec) {
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = period_usec;
timer.it_value = timer.it_interval;
- if (setitimer(ITIMER_PROF, &timer, 0) == -1) {
+ if (setitimer(ITIMER_PROF, &timer, nullptr) == -1) {
LOG(ERROR) << "Scheduling profiler interval failed with error " << errno;
return false;
}
@@ -168,7 +168,7 @@ bool SignalHandler::SetSigprofInterval(int64_t period_usec) {
struct sigaction SignalHandler::SetAction(void (*action)(int, siginfo_t *,
void *)) {
struct sigaction sa;
- sa.sa_handler = NULL;
+ sa.sa_handler = nullptr;
sa.sa_sigaction = action;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
diff --git a/src/proto.cc b/src/proto.cc
index 6dcd905c9..6c64d8ee3 100644
--- a/src/proto.cc
+++ b/src/proto.cc
@@ -231,6 +231,8 @@ void ProfileProtoBuilder::Populate(
sample_type->set_type(builder_.StringId(profile_type));
sample_type->set_unit(builder_.StringId("nanoseconds"));
+ profile->set_default_sample_type(builder_.StringId(profile_type));
+
profile->set_duration_nanos(duration_ns);
for (const auto &trace : traces) {
diff --git a/src/throttler.h b/src/throttler.h
index aa9bbcc9b..93de22497 100644
--- a/src/throttler.h
+++ b/src/throttler.h
@@ -26,6 +26,9 @@ namespace profiler {
constexpr char kTypeCPU[] = "cpu";
constexpr char kTypeWall[] = "wall";
constexpr char kTypeHeap[] = "heap";
+// contention and threads are not supported in Java but are needed here for C++
+constexpr char kTypeContention[] = "contention";
+constexpr char kTypeThreads[] = "threads";
// Iterator-like abstraction used to guide a profiling loop comprising of
// waiting for when the next profile may be collected and saving its data once
diff --git a/src/throttler_api.cc b/src/throttler_api.cc
index e3e6bf824..12832ebd9 100644
--- a/src/throttler_api.cc
+++ b/src/throttler_api.cc
@@ -14,6 +14,12 @@
#include "src/throttler_api.h"
+#include
+#include
+#include
+#include
+#include
+
#include
#include // NOLINT
#include
@@ -26,12 +32,6 @@
#include "google/devtools/cloudprofiler/v2/profiler.grpc.pb.h"
#include "google/protobuf/duration.pb.h" // NOLINT
#include "google/rpc/error_details.pb.h" // NOLINT
-#include "grpc/grpc_security.h"
-#include "grpc/support/log.h"
-#include "grpc/support/string_util.h"
-#include "grpcpp/create_channel.h"
-#include "grpcpp/security/credentials.h"
-#include "grpcpp/support/channel_arguments.h"
#include "third_party/javaprofiler/clock.h"
// API curated profiling configuration.
@@ -178,7 +178,7 @@ bool InitializeDeployment(CloudEnv* env, const std::string& labels,
if (!IsValidServiceName(service)) {
LOG(ERROR)
<< "Deployment service name '" << service
- << "' does not match pattern '^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$'";
+ << "' does not match pattern '^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$'";
return false;
}
d->set_target(service);
@@ -227,12 +227,12 @@ bool AddProfileLabels(api::Profile* p, const std::string& labels) {
} // namespace
// Returns true if the service name matches the regex
-// "^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$", and false otherwise.
+// "^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$", and false otherwise.
bool IsValidServiceName(std::string s) {
if (s.length() < 1 || s.length() > 255) {
return false;
}
- if (s[0] < 'a' || s[0] > 'z') {
+ if ((s[0] < 'a' || s[0] > 'z') && (s[0] < '0' || s[0] > '9')) {
return false;
}
if ((s.back() < 'a' || s.back() > 'z') &&
@@ -341,6 +341,12 @@ std::string APIThrottler::ProfileType() {
return kTypeWall;
case api::HEAP:
return kTypeHeap;
+ // contention and threads are not supported in Java but are needed here
+ // for C++
+ case api::CONTENTION:
+ return kTypeContention;
+ case api::THREADS:
+ return kTypeThreads;
default:
const std::string& pt_name = api::ProfileType_Name(pt);
LOG(ERROR) << "Unsupported profile type " << pt_name;
diff --git a/src/throttler_api.h b/src/throttler_api.h
index c4ee41314..9083beb3f 100644
--- a/src/throttler_api.h
+++ b/src/throttler_api.h
@@ -30,8 +30,6 @@
#include "src/cloud_env.h"
#include "src/throttler.h"
#include "google/devtools/cloudprofiler/v2/profiler.grpc.pb.h"
-#include "grpcpp/client_context.h"
-#include "grpcpp/support/status.h"
namespace cloud {
namespace profiler {
diff --git a/src/worker.cc b/src/worker.cc
index 08213d796..9349838a5 100644
--- a/src/worker.cc
+++ b/src/worker.cc
@@ -18,7 +18,6 @@
#include "src/profiler.h"
#include "src/throttler_api.h"
#include "src/throttler_timed.h"
-#include "google/devtools/cloudprofiler/v2/profiler.grpc.pb.h"
#include "third_party/javaprofiler/heap_sampler.h"
DEFINE_bool(cprof_enabled, true,
diff --git a/third_party/javaprofiler/accessors.h b/third_party/javaprofiler/accessors.h
index 004bfe945..ef100d1e3 100644
--- a/third_party/javaprofiler/accessors.h
+++ b/third_party/javaprofiler/accessors.h
@@ -69,17 +69,25 @@ class Accessors {
template
static inline FunctionType GetJvmFunction(const char *function_name) {
- // get handle to library
- static void *handle = dlopen("libjvm.so", RTLD_LAZY);
- if (handle == NULL) {
- return NULL;
+ static void *handle = GetJvmLibHandle();
+ if (handle == nullptr) {
+ return nullptr;
}
- // get address of function, return null if not found
+ // Get address of function, return null if not found
return bit_cast(dlsym(handle, function_name));
}
private:
+ static void *GetJvmLibHandle() {
+ void *handle = dlopen("libjvm.so", RTLD_LAZY);
+ if (handle != nullptr) {
+ return handle;
+ }
+
+ return dlopen(nullptr, RTLD_LAZY);
+ }
+
// This is subtle and potentially dangerous, read this carefully.
//
// In glibc, TLS access is not signal-async-safe, as they can call malloc for
diff --git a/third_party/javaprofiler/display.cc b/third_party/javaprofiler/display.cc
index 86b867880..bbdc37834 100644
--- a/third_party/javaprofiler/display.cc
+++ b/third_party/javaprofiler/display.cc
@@ -174,6 +174,10 @@ jint GetLineNumber(jvmtiEnv *jvmti, jmethodID method, jlocation location) {
if (entry_count == 1) {
return table_ptr[0].line_number;
}
+ if (location == 0) {
+ // Return method first line.
+ return table_ptr[0].line_number;
+ }
jlocation last_location = table_ptr[0].start_location;
for (int l = 1; l < entry_count; l++) {
diff --git a/third_party/javaprofiler/heap_sampler.cc b/third_party/javaprofiler/heap_sampler.cc
index 37d131950..8dc91dd50 100644
--- a/third_party/javaprofiler/heap_sampler.cc
+++ b/third_party/javaprofiler/heap_sampler.cc
@@ -14,14 +14,23 @@
* limitations under the License.
*/
+#include
+#include
+#include
+
+#include "third_party/javaprofiler/accessors.h"
#include "third_party/javaprofiler/heap_sampler.h"
#include "third_party/javaprofiler/profile_proto_builder.h"
+#include "third_party/javaprofiler/stacktrace_decls.h"
+#include "third_party/javaprofiler/stacktraces.h"
namespace {
-std::vector
+using google::javaprofiler::JVMPI_CallFrame;
+
+std::vector
TransformFrames(jvmtiFrameInfo *stack_frames, int count) {
- std::vector frames(count);
+ std::vector frames(count);
for (int i = 0; i < count; i++) {
// Note that technically this is not the line number; it is the location but
@@ -34,12 +43,76 @@ TransformFrames(jvmtiFrameInfo *stack_frames, int count) {
return frames;
}
+std::unique_ptr> GetTrace(JNIEnv *jni) {
+ std::unique_ptr> trace_result = nullptr;
+
+// Cannot use the fast stacktrace for standalone builds as their standard
+// libraries do not support getcontext.
+
+ return trace_result;
+}
+
+std::unique_ptr> GetTraceUsingJvmti(
+ JNIEnv *jni, jvmtiEnv *jvmti, jthread thread) {
+ jint count = 0;
+ jvmtiFrameInfo stack_frames[google::javaprofiler::kMaxFramesToCapture];
+
+ jvmtiError err =
+ jvmti->GetStackTrace(thread, 0, google::javaprofiler::kMaxFramesToCapture,
+ stack_frames, &count);
+
+ if (err != JVMTI_ERROR_NONE || count <= 0) {
+ return nullptr;
+ }
+
+ return std::unique_ptr>(
+ new std::vector(TransformFrames(stack_frames, count)));
+}
+
+static jstring GetClassName(JNIEnv *jni_env, jobject object,
+ jclass object_klass) {
+ jclass cls = jni_env->FindClass("java/lang/Class");
+ jmethodID get_name_id =
+ jni_env->GetMethodID(cls, "getName", "()Ljava/lang/String;");
+ jstring name_obj = static_cast(
+ jni_env->CallObjectMethod(object_klass, get_name_id));
+ return name_obj;
+}
+
+static jlong GetThreadId(JNIEnv *jni_env, jthread thread) {
+ jclass thread_class = jni_env->FindClass("java/lang/Thread");
+ jmethodID get_id_method_id = jni_env->GetMethodID(thread_class,
+ "getId", "()J");
+ jlong thread_id = jni_env->CallLongMethod(thread, get_id_method_id);
+ return thread_id;
+}
+
extern "C" JNIEXPORT void SampledObjectAlloc(jvmtiEnv *jvmti_env,
JNIEnv *jni_env, jthread thread,
jobject object,
jclass object_klass, jlong size) {
+ if (!google::javaprofiler::HeapMonitor::HasAllocationInstrumentation() &&
+ !google::javaprofiler::HeapMonitor::HasGarbageInstrumentation()) {
+ google::javaprofiler::HeapMonitor::AddSample(jni_env, thread, object,
+ object_klass, size, nullptr, 0,
+ 0);
+ return;
+ }
+ jstring class_name = GetClassName(jni_env, object, object_klass);
+ const char *name_str = jni_env->GetStringUTFChars(class_name, NULL);
+ int name_len = strlen(name_str);
+ jbyte *name_bytes = const_cast(
+ reinterpret_cast(name_str));
+
+ jlong thread_id = GetThreadId(jni_env, thread);
+
google::javaprofiler::HeapMonitor::AddSample(jni_env, thread, object,
- object_klass, size);
+ object_klass, size, name_bytes,
+ name_len, thread_id);
+ // Invoke all functions in HeapMonitor::alloc_inst_functions_
+ google::javaprofiler::HeapMonitor::InvokeAllocationInstrumentationFunctions(
+ thread_id, name_bytes, name_len, size, 0);
+ jni_env->ReleaseStringUTFChars(class_name, name_str);
}
extern "C" JNIEXPORT void GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
@@ -50,40 +123,52 @@ extern "C" JNIEXPORT void GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
namespace google {
namespace javaprofiler {
+
+const HeapEventStorage::GcCallback HeapMonitor::gc_callback_ =
+ [](const HeapObjectTrace &elem) {
+ HeapMonitor::InvokeGarbageInstrumentationFunctions(elem.ThreadId(),
+ elem.Name(),
+ elem.NameLength(),
+ elem.Size(),
+ 0);
+};
+
+std::atomic HeapMonitor::heap_monitor_;
+
std::atomic HeapMonitor::jvmti_;
std::atomic HeapMonitor::sampling_interval_;
-
-HeapEventStorage::HeapEventStorage(jvmtiEnv *jvmti, ProfileFrameCache *cache,
- int max_garbage_size)
+std::atomic HeapMonitor::use_jvm_trace_;
+std::vector
+ HeapMonitor::alloc_inst_functions_;
+std::vector
+ HeapMonitor::gc_inst_functions_;
+
+HeapEventStorage::HeapEventStorage(jvmtiEnv *jvmti,
+ ProfileFrameCache *cache,
+ int max_garbage_size,
+ GcCallback gc_callback)
: peak_profile_size_(0),
max_garbage_size_(max_garbage_size),
cur_garbage_pos_(0),
- jvmti_(jvmti), cache_(cache) {
+ jvmti_(jvmti), cache_(cache), gc_callback_(gc_callback) {
}
void HeapEventStorage::Add(JNIEnv *jni, jthread thread, jobject object,
- jclass klass, jlong size) {
- const int kMaxFrames = 128;
- jint count = 0;
- jvmtiFrameInfo stack_frames[kMaxFrames];
- jvmtiError err =
- jvmti_->GetStackTrace(thread, 0, kMaxFrames, stack_frames, &count);
-
- if (err == JVMTI_ERROR_NONE && count > 0) {
- auto frames = TransformFrames(stack_frames, count);
-
- jweak weak_ref = jni->NewWeakGlobalRef(object);
- if (jni->ExceptionCheck()) {
- LOG(WARNING) << "Failed to create NewWeakGlobalRef, skipping heap sample";
- return;
- }
+ jclass klass, jlong size,
+ const std::vector &&frames,
+ jbyte *name, jint name_len, jlong thread_id) {
+ jweak weak_ref = jni->NewWeakGlobalRef(object);
+ if (jni->ExceptionCheck()) {
+ LOG(WARNING) << "Failed to create NewWeakGlobalRef, skipping heap sample";
+ return;
+ }
- HeapObjectTrace live_object(weak_ref, size, std::move(frames));
+ HeapObjectTrace live_object(weak_ref, size, std::move(frames), name, name_len,
+ thread_id);
- // Only now lock and get things done quickly.
- std::lock_guard lock(storage_lock_);
- newly_allocated_objects_.push_back(std::move(live_object));
- }
+ // Only now lock and get things done quickly.
+ std::lock_guard lock(storage_lock_);
+ newly_allocated_objects_.push_back(std::move(live_object));
}
void HeapEventStorage::AddToGarbage(HeapObjectTrace &&obj) {
@@ -102,6 +187,7 @@ void HeapEventStorage::MoveLiveObjects(
if (elem.IsLive(env)) {
still_live_objects->push_back(std::move(elem));
} else {
+ gc_callback_(elem);
elem.DeleteWeakReference(env);
AddToGarbage(std::move(elem));
}
@@ -154,7 +240,7 @@ HeapEventStorage::StackTraceArrayBuilder::StackTraceArrayBuilder(
}
void HeapEventStorage::StackTraceArrayBuilder::AddTrace(
- HeapEventStorage::HeapObjectTrace &object) {
+ HeapObjectTrace &object) {
std::vector &frames = object.Frames();
call_trace_data_[curr_trace_] = {nullptr,
@@ -266,6 +352,74 @@ bool HeapMonitor::Supported(jvmtiEnv *jvmti) {
#endif
}
+void HeapMonitor::AddSample(JNIEnv *jni_env, jthread thread, jobject object,
+ jclass object_klass, jlong size, jbyte *name,
+ jint name_len, jlong thread_id) {
+ auto trace = use_jvm_trace_.load()
+ ? GetTrace(jni_env)
+ : GetTraceUsingJvmti(jni_env, jvmti_.load(), thread);
+ if (trace == nullptr) {
+ return;
+ }
+
+ GetInstance()->storage_.Add(jni_env, thread, object, object_klass, size,
+ std::move(*trace), name, name_len, thread_id);
+}
+
+void HeapMonitor::InvokeAllocationInstrumentationFunctions(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext) {
+ for (auto fn : GetInstance()->alloc_inst_functions_) {
+ fn(thread_id, name, name_length, size, gcontext);
+ }
+}
+
+void HeapMonitor::AddAllocationInstrumentation(
+ AllocationInstrumentationFunction fn) {
+ GetInstance()->alloc_inst_functions_.push_back(fn);
+}
+
+bool HeapMonitor::HasAllocationInstrumentation() {
+ return !GetInstance()->alloc_inst_functions_.empty();
+}
+
+bool HeapMonitor::HasGarbageInstrumentation() {
+ return !GetInstance()->gc_inst_functions_.empty();
+}
+
+void HeapMonitor::InvokeGarbageInstrumentationFunctions(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext) {
+ for (auto fn : GetInstance()->gc_inst_functions_) {
+ fn(thread_id, name, name_length, size, gcontext);
+ }
+}
+
+void HeapMonitor::AddGarbageInstrumentation(
+ GarbageInstrumentationFunction fn) {
+ GetInstance()->gc_inst_functions_.push_back(fn);
+}
+
+void HeapMonitor::ShutdownGCWaitingThread() {
+ GetInstance()->NotifyGCWaitingThreadInternal(GcEvent::SHUTDOWN);
+ GetInstance()->WaitForShutdown();
+}
+
+void HeapMonitor::WaitForShutdown() {
+ // Here we wait for the GC thread to process the shutdown event.
+ // We can't use JNI to call "Thread.join" on the thread as FindClass
+ // crashes if called in VM shutdown.
+
+ std::unique_lock lock(gc_waiting_mutex_);
+
+ // If we are woken up without having been notified, just go back to sleep.
+ gc_waiting_cv_.wait(lock, [this] { return gc_thread_shutdown; } );
+}
+
void HeapMonitor::AddCallback(jvmtiEventCallbacks *callbacks) {
#ifdef ENABLE_HEAP_SAMPLING
callbacks->SampledObjectAlloc = &SampledObjectAlloc;
@@ -274,7 +428,8 @@ void HeapMonitor::AddCallback(jvmtiEventCallbacks *callbacks) {
}
// Currently, we enable once and forget about it.
-bool HeapMonitor::Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval) {
+bool HeapMonitor::Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval,
+ bool use_jvm_trace) {
#ifdef ENABLE_HEAP_SAMPLING
if (!Supported(jvmti)) {
LOG(WARNING) << "Heap sampling is not supported by the JVM, disabling the "
@@ -282,6 +437,16 @@ bool HeapMonitor::Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval) {
return false;
}
+ jvmti_.store(jvmti);
+ sampling_interval_.store(sampling_interval);
+ use_jvm_trace_.store(use_jvm_trace);
+
+ // Ensure this is really a singleton i.e. don't recreate it if sampling is
+ // re-enabled.
+ if (heap_monitor_ == nullptr) {
+ heap_monitor_.store(new HeapMonitor());
+ }
+
jvmtiCapabilities caps;
memset(&caps, 0, sizeof(caps));
// Get line numbers, sample events, and filename for the tests.
@@ -302,9 +467,6 @@ bool HeapMonitor::Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval) {
return false;
}
- jvmti_.store(jvmti);
- sampling_interval_.store(sampling_interval);
-
if (!GetInstance()->CreateGCWaitingThread(jvmti, jni)) {
return false;
}
@@ -328,6 +490,10 @@ bool HeapMonitor::Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval) {
return false;
}
+ if (use_jvm_trace) {
+ Asgct::SetAsgct(Accessors::GetJvmFunction("AsyncGetCallTrace"));
+ }
+
return true;
#else
return false;
@@ -428,6 +594,9 @@ void HeapMonitor::GCWaitingThreadRun(JNIEnv* jni_env) {
// Was the heap monitor disabled?
if (event == GcEvent::SHUTDOWN) {
+ std::unique_lock lock(gc_waiting_mutex_);
+ gc_thread_shutdown = true;
+ gc_waiting_cv_.notify_all();
break;
}
diff --git a/third_party/javaprofiler/heap_sampler.h b/third_party/javaprofiler/heap_sampler.h
index bd830cefe..48eafc177 100644
--- a/third_party/javaprofiler/heap_sampler.h
+++ b/third_party/javaprofiler/heap_sampler.h
@@ -20,24 +20,111 @@
#include
#include
+#include
#include // NOLINT
+#include
#include
#include
#include // NOLINT
#include
-#include "third_party/javaprofiler/globals.h"
#include "third_party/javaprofiler/profile_proto_builder.h"
+typedef void (*AllocationInstrumentationFunction)(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext);
+
+typedef void (*GarbageInstrumentationFunction)(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext);
+
namespace google {
namespace javaprofiler {
+// A sampled heap object, defined by the object, its size, and the stack
+// frame.
+class HeapObjectTrace {
+ public:
+ // This object owns the jweak object parameter. It is freed when the object
+ // is sent to the garbage list, and the object is set to nullptr.
+ HeapObjectTrace(jweak object, jlong size,
+ const std::vector &&frames, jbyte *name,
+ int name_length, jlong thread_id)
+ : object_(object), size_(size), frames_(std::move(frames)),
+ name_(name), name_length_(name_length), thread_id_(thread_id) {}
+
+ HeapObjectTrace(jweak object, jlong size,
+ const std::vector &frames)
+ : object_(object), size_(size), frames_(frames) {}
+
+ // Allow moving.
+ HeapObjectTrace(HeapObjectTrace&& o) = default;
+ HeapObjectTrace& operator=(HeapObjectTrace&& o) = default;
+
+ // No copying allowed.
+ HeapObjectTrace(const HeapObjectTrace& o) = delete;
+ HeapObjectTrace& operator=(const HeapObjectTrace& o) = delete;
+
+ std::vector &Frames() {
+ return frames_;
+ }
+
+ int Size() const {
+ return size_;
+ }
+
+ jbyte *Name() const {
+ return name_;
+ }
+
+ int NameLength() const {
+ return name_length_;
+ }
+
+ jlong ThreadId() const {
+ return thread_id_;
+ }
+
+ void DeleteWeakReference(JNIEnv* env) {
+ env->DeleteWeakGlobalRef(object_);
+ object_ = nullptr;
+ }
+
+ bool IsLive(JNIEnv *env) {
+ // When GC collects the object, the object represented by the weak
+ // reference will be considered as the same object as NULL.
+ return !env->IsSameObject(object_, NULL);
+ }
+
+ // Make copying an explicit operation for the one case we need it (adding
+ // to the peak heapz storage)
+ HeapObjectTrace Copy() {
+ return HeapObjectTrace(object_, size_, frames_);
+ }
+
+ private:
+ jweak object_;
+ int size_;
+ std::vector frames_;
+ jbyte *name_;
+ int name_length_;
+ jlong thread_id_;
+};
+
// Storage for the sampled heap objects recorded from the heap sampling JVMTI
// API callbacks.
class HeapEventStorage {
public:
- HeapEventStorage(jvmtiEnv *jvmti, ProfileFrameCache *cache = nullptr,
- int max_garbage_size = 200);
+ typedef std::function GcCallback;
+
+ HeapEventStorage(jvmtiEnv *jvmti,
+ ProfileFrameCache *cache = nullptr,
+ int max_garbage_size = 200,
+ GcCallback gc_callback = [](const HeapObjectTrace &t){});
// TODO: establish correct shutdown sequence: how do we ensure that
// things are not going to go awfully wrong at shutdown, is it this class' job
@@ -45,7 +132,8 @@ class HeapEventStorage {
// Adds an object to the storage system.
void Add(JNIEnv *jni, jthread thread, jobject object, jclass klass,
- jlong size);
+ jlong size, const std::vector &&frames, jbyte *name,
+ jint name_len, jlong thread_id);
// Returns a perftools::profiles::Profile with the objects stored via
// calls to the Add method.
@@ -78,66 +166,13 @@ class HeapEventStorage {
HeapEventStorage& operator=(const HeapEventStorage&) = delete;
private:
- // A sampled heap object, defined by the object, its size, and the stack
- // frame.
- class HeapObjectTrace {
- public:
- // This object owns the jweak object parameter. It is freed when the object
- // is sent to the garbage list, and the object is set to nullptr.
- HeapObjectTrace(jweak object, jlong size,
- const std::vector &&frames)
- : object_(object), size_(size), frames_(std::move(frames)) {}
-
- HeapObjectTrace(jweak object, jlong size,
- const std::vector &frames)
- : object_(object), size_(size), frames_(frames) {}
-
- // Allow moving.
- HeapObjectTrace(HeapObjectTrace&& o) = default;
- HeapObjectTrace& operator=(HeapObjectTrace&& o) = default;
-
- // No copying allowed.
- HeapObjectTrace(const HeapObjectTrace& o) = delete;
- HeapObjectTrace& operator=(const HeapObjectTrace& o) = delete;
-
- std::vector &Frames() {
- return frames_;
- }
-
- int Size() const {
- return size_;
- }
-
- void DeleteWeakReference(JNIEnv* env) {
- env->DeleteWeakGlobalRef(object_);
- object_ = nullptr;
- }
-
- bool IsLive(JNIEnv *env) {
- // When GC collects the object, the object represented by the weak
- // reference will be considered as the same object as NULL.
- return !env->IsSameObject(object_, NULL);
- }
-
- // Make copying an explicit operation for the one case we need it (adding
- // to the peak heapz storage)
- HeapObjectTrace Copy() {
- return HeapObjectTrace(object_, size_, frames_);
- }
-
- private:
- jweak object_;
- int size_;
- std::vector frames_;
- };
-
// Helper for creating a google::javaprofiler::ProfileStackTrace array
// to pass to ProfileProtoBuilder.
class StackTraceArrayBuilder {
public:
StackTraceArrayBuilder(std::size_t objects_size);
- void AddTrace(HeapEventStorage::HeapObjectTrace &object);
+ void AddTrace(HeapObjectTrace &object);
google::javaprofiler::ProfileStackTrace* GetStackTraceData() const {
return stack_trace_data_.get();
@@ -146,7 +181,8 @@ class HeapEventStorage {
private:
int curr_trace_ = 0;
std::size_t objects_size_;
- std::unique_ptr stack_trace_data_;
+ std::unique_ptr
+ stack_trace_data_;
std::unique_ptr call_trace_data_;
};
@@ -185,12 +221,14 @@ class HeapEventStorage {
std::mutex storage_lock_;
jvmtiEnv *jvmti_;
ProfileFrameCache *cache_;
+ const GcCallback gc_callback_;
};
// Due to the JVMTI callback, everything here is static.
class HeapMonitor {
public:
- static bool Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval);
+ static bool Enable(jvmtiEnv *jvmti, JNIEnv* jni, int sampling_interval,
+ bool use_jvm_trace);
static void Disable();
static bool Enabled() { return jvmti_ != nullptr; }
@@ -210,9 +248,29 @@ class HeapMonitor {
JNIEnv* env, bool force_gc);
static void AddSample(JNIEnv *jni_env, jthread thread, jobject object,
- jclass object_klass, jlong size) {
- GetInstance()->storage_.Add(jni_env, thread, object, object_klass, size);
- }
+ jclass object_klass, jlong size, jbyte *name,
+ jint name_len, jlong thread_id);
+
+ static void InvokeAllocationInstrumentationFunctions(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext);
+
+ static void AddAllocationInstrumentation(
+ AllocationInstrumentationFunction fn);
+
+ static bool HasAllocationInstrumentation();
+
+ static void InvokeGarbageInstrumentationFunctions(jlong thread_id,
+ jbyte *name,
+ int name_length,
+ int size,
+ jlong gcontext);
+
+ static void AddGarbageInstrumentation(GarbageInstrumentationFunction fn);
+
+ static bool HasGarbageInstrumentation();
static void AddCallback(jvmtiEventCallbacks *callbacks);
@@ -220,22 +278,30 @@ class HeapMonitor {
GetInstance()->NotifyGCWaitingThreadInternal(GcEvent::GC_FINISHED);
}
- static void ShutdownGCWaitingThread() {
- GetInstance()->NotifyGCWaitingThreadInternal(GcEvent::SHUTDOWN);
- }
+ static void ShutdownGCWaitingThread();
// Not copyable or movable.
HeapMonitor(const HeapMonitor &) = delete;
HeapMonitor &operator=(const HeapMonitor &) = delete;
private:
- HeapMonitor() : storage_(jvmti_.load()) {}
+ static const HeapEventStorage::GcCallback gc_callback_;
+
+ HeapMonitor() : storage_(jvmti_.load(), GetFrameCache(), 200, gc_callback_) {
+ }
- // We construct the heap_monitor at the first call to GetInstance, so ensure
- // Enable was called at least once before to initialize jvmti_.
+ static std::atomic heap_monitor_;
+
+ // We initialize heap_monitor_ in Enable, so ensure Enable is called before
+ // any call to this method.
static HeapMonitor *GetInstance() {
- static HeapMonitor heap_monitor;
- return &heap_monitor;
+ assert(heap_monitor_ != nullptr);
+ return heap_monitor_;
+ }
+
+ ProfileFrameCache *GetFrameCache() {
+ ProfileFrameCache *cache = nullptr;
+ return cache;
}
static bool Supported(jvmtiEnv* jvmti);
@@ -251,16 +317,21 @@ class HeapMonitor {
void GCWaitingThreadRun(JNIEnv* jni_env);
GcEvent WaitForGC();
void NotifyGCWaitingThreadInternal(GcEvent event);
+ void WaitForShutdown();
void CompactData(JNIEnv* jni_env);
+ static std::vector alloc_inst_functions_;
+ static std::vector gc_inst_functions_;
static std::unique_ptr EmptyHeapProfile(
JNIEnv *jni_env);
static std::atomic jvmti_;
static std::atomic sampling_interval_;
+ static std::atomic use_jvm_trace_;
std::list gc_notify_events_;
+ bool gc_thread_shutdown = false;
std::condition_variable gc_waiting_cv_;
std::mutex gc_waiting_mutex_;
HeapEventStorage storage_;
diff --git a/third_party/javaprofiler/method_info.h b/third_party/javaprofiler/method_info.h
index a66f81a5b..b3c91742e 100644
--- a/third_party/javaprofiler/method_info.h
+++ b/third_party/javaprofiler/method_info.h
@@ -34,10 +34,11 @@ class MethodInfo {
public:
// Constructor providing all the information regarding a method.
MethodInfo(const std::string &method_name, const std::string &class_name,
- const std::string &file_name)
+ const std::string &file_name, const int &start_line)
: method_name_(method_name),
class_name_(class_name),
- file_name_(file_name) {}
+ file_name_(file_name),
+ start_line_(start_line) {}
// An invalid location Id.
static const int64 kInvalidLocationId = 0;
@@ -57,10 +58,13 @@ class MethodInfo {
const std::string &FileName() const { return file_name_; }
+ const int& StartLine() const { return start_line_; }
+
private:
std::string method_name_;
std::string class_name_;
std::string file_name_;
+ int start_line_;
// Cache of jlocation results.
std::unordered_map locations_;
diff --git a/third_party/javaprofiler/profile_proto_builder.cc b/third_party/javaprofiler/profile_proto_builder.cc
index 9f764406d..4ebacbc3d 100644
--- a/third_party/javaprofiler/profile_proto_builder.cc
+++ b/third_party/javaprofiler/profile_proto_builder.cc
@@ -43,6 +43,9 @@ ProfileProtoBuilder::ProfileProtoBuilder(JNIEnv *jni_env, jvmtiEnv *jvmti_env,
location_builder_(&builder_) {
AddSampleType(count_type);
AddSampleType(metric_type);
+ builder_.mutable_profile()->set_default_sample_type(
+ builder_.StringId(metric_type.type.c_str()));
+
SetPeriodType(metric_type);
}
@@ -72,7 +75,7 @@ void ProfileProtoBuilder::AddTraces(const ProfileStackTrace *traces,
void ProfileProtoBuilder::AddArtificialTrace(const std::string &name, int count,
int sampling_rate) {
perftools::profiles::Location *location = location_builder_.LocationFor(
- name, name, "", -1);
+ name, name, "", 0, -1, 0);
auto profile = builder_.mutable_profile();
auto sample = profile->add_sample();
@@ -178,15 +181,13 @@ void ProfileProtoBuilder::AddTrace(const ProfileStackTrace &profile_trace,
const JVMPI_CallTrace *trace = trace_and_labels.trace;
int first_frame = SkipTopNativeFrames(*trace);
- StackState stack_state;
-
for (int i = first_frame; i < trace->num_frames; ++i) {
auto &jvm_frame = trace->frames[i];
if (jvm_frame.lineno == kNativeFrameLineNum) {
- AddNativeInfo(jvm_frame, profile, sample, &stack_state);
+ AddNativeInfo(jvm_frame, profile, sample);
} else {
- AddJavaInfo(jvm_frame, profile, sample, &stack_state);
+ AddJavaInfo(jvm_frame, profile, sample);
}
}
}
@@ -194,13 +195,10 @@ void ProfileProtoBuilder::AddTrace(const ProfileStackTrace &profile_trace,
void ProfileProtoBuilder::AddJavaInfo(
const JVMPI_CallFrame &jvm_frame,
perftools::profiles::Profile *profile,
- perftools::profiles::Sample *sample,
- StackState *stack_state) {
- stack_state->JavaFrame();
-
+ perftools::profiles::Sample *sample) {
if (!jvm_frame.method_id) {
perftools::profiles::Location *location = location_builder_.LocationFor(
- "", "[Unknown method]", "", 0);
+ "", "[Unknown method]", "", 0, 0, 0);
sample->add_location_id(location->id());
return;
}
@@ -210,7 +208,7 @@ void ProfileProtoBuilder::AddJavaInfo(
}
int64 ProfileProtoBuilder::Location(MethodInfo *method,
- const JVMPI_CallFrame &frame) {
+ const JVMPI_CallFrame &frame) {
// lineno is actually the BCI of the frame.
int bci = frame.lineno;
@@ -227,7 +225,9 @@ int64 ProfileProtoBuilder::Location(MethodInfo *method,
location_builder_.LocationFor(method->ClassName(),
method->MethodName(),
method->FileName(),
- line_number);
+ method->StartLine(),
+ line_number,
+ 0);
method->AddLocation(bci, location->id());
return location->id();
@@ -243,17 +243,18 @@ MethodInfo *ProfileProtoBuilder::Method(jmethodID method_id) {
std::string class_name;
std::string method_name;
std::string signature;
+ int start_line = 0;
- // Ignore lineno since we pass nullptr anyway.
+ // Set lineno to zero to get method first line.
JVMPI_CallFrame jvm_frame = { 0, method_id };
GetStackFrameElements(jni_env_, jvmti_env_, jvm_frame, &file_name,
- &class_name, &method_name, &signature, nullptr);
+ &class_name, &method_name, &signature, &start_line);
FixMethodParameters(&signature);
std::string full_method_name = class_name + "." + method_name + signature;
std::unique_ptr unique_method(
- new MethodInfo(full_method_name, class_name, file_name));
+ new MethodInfo(full_method_name, class_name, file_name, start_line));
auto method_ptr = unique_method.get();
methods_[method_id] = std::move(unique_method);
@@ -262,11 +263,11 @@ MethodInfo *ProfileProtoBuilder::Method(jmethodID method_id) {
void ProfileProtoBuilder::AddNativeInfo(const JVMPI_CallFrame &jvm_frame,
perftools::profiles::Profile *profile,
- perftools::profiles::Sample *sample,
- StackState *stack_state) {
+ perftools::profiles::Sample *sample) {
if (!native_cache_) {
+ int64_t address = reinterpret_cast(jvm_frame.method_id);
perftools::profiles::Location *location = location_builder_.LocationFor(
- "", "[Unknown non-Java frame]", "", 0);
+ "", "[Unknown non-Java frame]", "", 0, 0, address);
sample->add_location_id(location->id());
return;
}
@@ -282,12 +283,7 @@ void ProfileProtoBuilder::AddNativeInfo(const JVMPI_CallFrame &jvm_frame,
&location_builder_);
- stack_state->NativeFrame(function_name);
-
- if (!stack_state->SkipFrame()) {
- location->set_address(reinterpret_cast(jvm_frame.method_id));
- sample->add_location_id(location->id());
- }
+ sample->add_location_id(location->id());
}
void ContentionProfileProtoBuilder::MultiplyBySamplingRate() {
@@ -317,6 +313,7 @@ size_t LocationBuilder::LocationInfoHash::operator()(
h = 31U * h + hash_string(info.function_name);
h = 31U * h + hash_string(info.file_name);
h = 31U * h + hash_int(info.line_number);
+ h = 31U * h + hash_int(info.address);
return h;
}
@@ -326,15 +323,31 @@ bool LocationBuilder::LocationInfoEquals::operator()(
return info1.class_name == info2.class_name &&
info1.function_name == info2.function_name &&
info1.file_name == info2.file_name &&
- info1.line_number == info2.line_number;
+ info1.line_number == info2.line_number &&
+ info1.address == info2.address;
}
perftools::profiles::Location *LocationBuilder::LocationFor(
const std::string &class_name, const std::string &function_name,
- const std::string &file_name, int line_number) {
+ const std::string &file_name, int start_line, int line_number,
+ int64_t address) {
auto profile = builder_->mutable_profile();
- LocationInfo info{ class_name, function_name, file_name, line_number };
+ // Adjust address by -1, so that the address is within the call instruction
+ // instead of at the start of the return instruction, as per
+ // go/new-z-page#ret-addr-fixup
+ //
+ // We use 0 (NULL) to indicate the absence of a valid address, and so
+ // do not do this where it would be invalid i.e. leading to -1
+ address = (address > 0) ? address - 1 : 0;
+
+ LocationInfo info {
+ class_name,
+ function_name,
+ file_name,
+ line_number,
+ address
+ };
if (locations_.count(info) > 0) {
return locations_.find(info)->second;
@@ -343,6 +356,7 @@ perftools::profiles::Location *LocationBuilder::LocationFor(
auto location_id = profile->location_size() + 1;
perftools::profiles::Location *location = profile->add_location();
location->set_id(location_id);
+ location->set_address(address);
locations_[info] = location;
@@ -350,8 +364,9 @@ perftools::profiles::Location *LocationBuilder::LocationFor(
std::string simplified_name = function_name;
SimplifyFunctionName(&simplified_name);
- auto function_id = builder_->FunctionId(
- simplified_name.c_str(), function_name.c_str(), file_name.c_str(), 0);
+ auto function_id =
+ builder_->FunctionId(simplified_name.c_str(), function_name.c_str(),
+ file_name.c_str(), start_line);
line->set_function_id(function_id);
line->set_line(line_number);
diff --git a/third_party/javaprofiler/profile_proto_builder.h b/third_party/javaprofiler/profile_proto_builder.h
index ec29c5f4a..5814a6d0e 100644
--- a/third_party/javaprofiler/profile_proto_builder.h
+++ b/third_party/javaprofiler/profile_proto_builder.h
@@ -168,7 +168,9 @@ class LocationBuilder {
perftools::profiles::Location *LocationFor(const std::string &class_name,
const std::string &function_name,
const std::string &file_name,
- int line_number);
+ int start_line,
+ int line_number,
+ int64_t address);
private:
struct LocationInfo {
@@ -176,6 +178,7 @@ class LocationBuilder {
std::string function_name;
std::string file_name;
int line_number;
+ int64_t address;
};
struct LocationInfoHash {
@@ -288,43 +291,6 @@ class ProfileProtoBuilder {
int64 sampling_rate_ = 0;
private:
- // Track progress through a stack as we traverse it, in order to determine
- // how processing should proceed based on the context of a frame.
- class StackState {
- public:
- StackState() {
- }
-
- // Notify the state that we are visiting a Java frame.
- void JavaFrame() {
- in_jni_helpers_ = false;
- }
-
- // Notify the state that we are visiting a native frame.
- void NativeFrame(const std::string &function_name) {
- if (StartsWith(function_name, "JavaCalls::call_helper")) {
- in_jni_helpers_ = true;
- }
- }
-
- // Should we skip the current frame?
- bool SkipFrame() const {
- return in_jni_helpers_;
- }
-
- private:
- // We don't add native frames that are just "helper" native code for
- // dispatching to JNI code. We determine this by detecting a native
- // JavaCalls::call_helper frame, then skipping until the we see a Java
- // frame again.
- // TODO: Support a "complete detail" mode to override this.
- bool in_jni_helpers_ = false;
-
- static bool StartsWith(const std::string &s, const std::string &prefix) {
- return s.find(prefix) == 0;
- }
- };
-
void AddSampleType(const SampleType &sample_type);
void SetPeriodType(const SampleType &metric_type);
void InitSampleValues(perftools::profiles::Sample *sample, int64 count,
@@ -334,12 +300,10 @@ class ProfileProtoBuilder {
void AddTrace(const ProfileStackTrace &trace, int32 count);
void AddJavaInfo(const JVMPI_CallFrame &jvm_frame,
perftools::profiles::Profile *profile,
- perftools::profiles::Sample *sample,
- StackState *stack_state);
+ perftools::profiles::Sample *sample);
void AddNativeInfo(const JVMPI_CallFrame &jvm_frame,
perftools::profiles::Profile *profile,
- perftools::profiles::Sample *sample,
- StackState *stack_state);
+ perftools::profiles::Sample *sample);
void UnsampleMetrics();
MethodInfo *Method(jmethodID id);
@@ -441,6 +405,8 @@ class ContentionProfileProtoBuilder : public ProfileProtoBuilder {
ProfileProtoBuilder::SampleType("delay", "microseconds")) {
builder_.mutable_profile()->set_duration_nanos(duration_nanos);
builder_.mutable_profile()->set_period(sampling_rate);
+ builder_.mutable_profile()->set_default_sample_type(
+ builder_.StringId("delay"));
}
std::unique_ptr CreateProto() {
diff --git a/third_party/javaprofiler/profile_test_lib.cc b/third_party/javaprofiler/profile_test_lib.cc
index 701dc69ed..f41c6f996 100644
--- a/third_party/javaprofiler/profile_test_lib.cc
+++ b/third_party/javaprofiler/profile_test_lib.cc
@@ -177,6 +177,25 @@ static jvmtiError GetStackTrace(jvmtiEnv* env, jthread thread, jint start_depth,
return JVMTI_ERROR_NONE;
}
+std::vector CreateStackTrace(int i) {
+ std::vector frames;
+
+ switch (i) {
+ case 0:
+ frames.push_back({30, reinterpret_cast(1)});
+ frames.push_back({64, reinterpret_cast(2)});
+ break;
+ case 1:
+ frames.push_back({128, reinterpret_cast(3)});
+ break;
+ default:
+ // Add nothing
+ ;
+ }
+
+ return frames;
+}
+
static jvmtiError ForceGarbageCollection(jvmtiEnv* env) {
return JVMTI_ERROR_NONE;
}
diff --git a/third_party/javaprofiler/profile_test_lib.h b/third_party/javaprofiler/profile_test_lib.h
index 1f0655700..c0251e49e 100644
--- a/third_party/javaprofiler/profile_test_lib.h
+++ b/third_party/javaprofiler/profile_test_lib.h
@@ -76,6 +76,8 @@ class JvmProfileTestLib {
static std::atomic method_name_call_count;
};
+std::vector CreateStackTrace(int i);
+
} // namespace javaprofiler
} // namespace google
diff --git a/third_party/perftools/profiles/proto/builder.cc b/third_party/perftools/profiles/proto/builder.cc
index 428cf93d7..62e253bfb 100644
--- a/third_party/perftools/profiles/proto/builder.cc
+++ b/third_party/perftools/profiles/proto/builder.cc
@@ -121,8 +121,9 @@ bool Builder::MarshalToFile(const Profile &profile, int fd) {
bool Builder::MarshalToFile(const Profile &profile, const char *filename) {
int fd;
- while ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0444)) < 0 &&
- errno == EINTR) {}
+ while ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0 &&
+ errno == EINTR) {
+ }
if (fd == -1) {
PLOG(ERROR) << "Failed to open file " << filename;
return false;
@@ -192,6 +193,26 @@ bool Builder::CheckValid(const Profile &profile) {
return false;
}
+ const int default_sample_type = profile.default_sample_type();
+ if (default_sample_type <= 0 ||
+ default_sample_type >= profile.string_table_size()) {
+ LOG(ERROR) << "No default sample type specified";
+ return false;
+ }
+
+ std::unordered_set value_types;
+ for (const auto &sample_type : profile.sample_type()) {
+ if (!value_types.insert(sample_type.type()).second) {
+ LOG(ERROR) << "Duplicate sample_type specified";
+ return false;
+ }
+ }
+
+ if (value_types.count(default_sample_type) == 0) {
+ LOG(ERROR) << "Default sample type not found";
+ return false;
+ }
+
for (const auto &sample : profile.sample()) {
if (sample.value_size() != sample_type_len) {
LOG(ERROR) << "Found sample with " << sample.value_size()