diff --git a/src/pem_roots.cc b/src/pem_roots.cc index b967de70e..7a3cf8711 100644 --- a/src/pem_roots.cc +++ b/src/pem_roots.cc @@ -54,37 +54,6 @@ ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -# Operating CA: DigiCert -# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc -# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc -# Label: "Cybertrust Global Root" -# Serial: 4835703278459682877484360 -# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 -# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 -# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG -A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh -bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE -ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS -b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 -7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS -J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y -HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP -t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz -FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY -XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw -hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js -MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA -A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj -Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx -XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o -omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc -A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- - # Operating CA: DigiCert # Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com # Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com @@ -330,35 +299,6 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- -# Operating CA: DigiCert -# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. -# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. -# Label: "GeoTrust Global CA" -# Serial: 144470 -# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 -# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 -# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- - # Operating CA: Entrust Datacard # Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. # Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. @@ -866,37 +806,6 @@ dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- -# Operating CA: Google Trust Services LLC -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Label: "GlobalSign Root CA - R2" -# Serial: 4835703278459682885658125 -# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 -# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe -# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------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 diff --git a/src/throttler.h b/src/throttler.h index 5cba00e47..aa9bbcc9b 100644 --- a/src/throttler.h +++ b/src/throttler.h @@ -19,8 +19,6 @@ #include -#include "src/globals.h" - namespace cloud { namespace profiler { diff --git a/src/throttler_api.cc b/src/throttler_api.cc index cd0d10996..e3e6bf824 100644 --- a/src/throttler_api.cc +++ b/src/throttler_api.cc @@ -32,6 +32,7 @@ #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. DEFINE_string(cprof_api_address, "cloudprofiler.googleapis.com", @@ -268,7 +269,8 @@ APIThrottler::APIThrottler( clock_(clock), stub_(std::move(stub)), creation_backoff_envelope_ns_(kBackoffNanos), - closed_(false) { + closed_(false), + backing_off_for_testing_(false) { grpc_init(); gpr_set_log_function(GRPCLog); @@ -321,10 +323,10 @@ bool APIThrottler::WaitNext() { creation_backoff_envelope_ns_ = kBackoffNanos; break; } + OnCreationError(st); if (closed_) { return false; } - OnCreationError(st); } return true; @@ -390,7 +392,7 @@ void APIThrottler::OnCreationError(const grpc::Status& st) { if (backoff_ns > 0) { LOG(INFO) << "Got ABORTED, will retry after backing off for " << backoff_ns / kNanosPerMilli << "ms"; - clock_->SleepFor(NanosToTimeSpec(backoff_ns)); + BackOff(NanosToTimeSpec(backoff_ns)); return; } } @@ -399,8 +401,7 @@ void APIThrottler::OnCreationError(const grpc::Status& st) { LOG(WARNING) << "Failed to create profile, will retry: " << DebugString(st); double random_factor = static_cast(dist_(gen_)) / kRandomRange; - clock_->SleepFor( - NanosToTimeSpec(creation_backoff_envelope_ns_ * random_factor)); + BackOff(NanosToTimeSpec(creation_backoff_envelope_ns_ * random_factor)); creation_backoff_envelope_ns_ = std::min( static_cast(creation_backoff_envelope_ns_ * kBackoffFactor), kMaxBackoffNanos); @@ -426,5 +427,19 @@ void APIThrottler::Close() { } } +void APIThrottler::BackOff(timespec ts) { + backing_off_for_testing_ = true; + auto end = TimeAdd(clock_->Now(), ts); + // Poll every 0.5s in case the throttler is closed during the backoff. + const timespec poll_interval = {0, 500 * 1000 * 1000}; // 0.5s + while (!closed_ && !AlmostThere(clock_, end, poll_interval)) { + clock_->SleepFor(poll_interval); + } + if (!closed_) { + clock_->SleepUntil(end); + } + backing_off_for_testing_ = false; +} + } // namespace profiler } // namespace cloud diff --git a/src/throttler_api.h b/src/throttler_api.h index d087cc87f..c4ee41314 100644 --- a/src/throttler_api.h +++ b/src/throttler_api.h @@ -62,6 +62,7 @@ class APIThrottler : public Throttler { private: FRIEND_TEST(APIThrottlerTest, TestCreatesAndUploadsProfile); + FRIEND_TEST(APIThrottlerTest, TestCloseInterruptsBackOff); // Takes a backoff on profile creation error. The backoff duration // may be specified by the server. Otherwise it will be a randomized // exponentially increasing value, bounded by kMaxBackoffNanos. @@ -70,6 +71,9 @@ class APIThrottler : public Throttler { // Resets the client gRPC context for the next call. void ResetClientContext(); + // Back off for a given duration. + void BackOff(timespec ts); + private: const std::vector types_; const std::string language_; @@ -90,6 +94,10 @@ class APIThrottler : public Throttler { std::atomic closed_; std::mutex ctx_mutex_; std::unique_ptr ctx_; + + // When true, indicates that the throttler is backing off. + // For testing only. + std::atomic backing_off_for_testing_; }; // Returns true if the service name matches the regex diff --git a/third_party/javaprofiler/heap_sampler.cc b/third_party/javaprofiler/heap_sampler.cc index e8c2b0dae..37d131950 100644 --- a/third_party/javaprofiler/heap_sampler.cc +++ b/third_party/javaprofiler/heap_sampler.cc @@ -19,18 +19,16 @@ namespace { -std::unique_ptr> +std::vector TransformFrames(jvmtiFrameInfo *stack_frames, int count) { - auto frames = - std::unique_ptr>( - new std::vector(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 // our CPU profiler piggy-backs on JVMPI_CallFrame and uses lineno as a // jlocation as well... - (*frames)[i].lineno = stack_frames[i].location; - (*frames)[i].method_id = stack_frames[i].method; + frames[i].lineno = stack_frames[i].location; + frames[i].method_id = stack_frames[i].method; } return frames; @@ -57,7 +55,8 @@ std::atomic HeapMonitor::sampling_interval_; HeapEventStorage::HeapEventStorage(jvmtiEnv *jvmti, ProfileFrameCache *cache, int max_garbage_size) - : max_garbage_size_(max_garbage_size), + : peak_profile_size_(0), + max_garbage_size_(max_garbage_size), cur_garbage_pos_(0), jvmti_(jvmti), cache_(cache) { } @@ -79,8 +78,7 @@ void HeapEventStorage::Add(JNIEnv *jni, jthread thread, jobject object, return; } - auto live_object = std::unique_ptr( - new HeapObjectTrace(weak_ref, size, std::move(frames))); + HeapObjectTrace live_object(weak_ref, size, std::move(frames)); // Only now lock and get things done quickly. std::lock_guard lock(storage_lock_); @@ -88,7 +86,7 @@ void HeapEventStorage::Add(JNIEnv *jni, jthread thread, jobject object, } } -void HeapEventStorage::AddToGarbage(std::unique_ptr obj) { +void HeapEventStorage::AddToGarbage(HeapObjectTrace &&obj) { if (garbage_objects_.size() >= max_garbage_size_) { garbage_objects_[cur_garbage_pos_] = std::move(obj); cur_garbage_pos_ = (cur_garbage_pos_ + 1) % max_garbage_size_; @@ -98,22 +96,31 @@ void HeapEventStorage::AddToGarbage(std::unique_ptr obj) { } void HeapEventStorage::MoveLiveObjects( - JNIEnv *env, std::vector> *objects, - std::vector> *still_live_objects) { + JNIEnv *env, std::vector *objects, + std::vector *still_live_objects) { for (auto &elem : *objects) { - if (elem->IsLive(env)) { + if (elem.IsLive(env)) { still_live_objects->push_back(std::move(elem)); } else { - elem->DeleteWeakReference(env); + elem.DeleteWeakReference(env); AddToGarbage(std::move(elem)); } } } +int64_t HeapEventStorage::ProfileSize( + const std::vector &live_objects) const { + int64_t total = 0; + for (auto &trace : live_objects) { + total += trace.Size(); + } + return total; +} + void HeapEventStorage::CompactSamples(JNIEnv *env) { std::lock_guard lock(storage_lock_); - std::vector> still_live; + std::vector still_live; MoveLiveObjects(env, &newly_allocated_objects_, &still_live); MoveLiveObjects(env, &live_objects_, &still_live); @@ -123,38 +130,67 @@ void HeapEventStorage::CompactSamples(JNIEnv *env) { // Newly allocated objects is now reset, those still alive are now in // live_objects. newly_allocated_objects_.clear(); + + // Update peak profile if needed. + + int64_t curr_profile_size = ProfileSize(live_objects_); + + if (curr_profile_size > peak_profile_size_) { + peak_profile_size_ = curr_profile_size; + + peak_objects_.clear(); + for (auto &object : live_objects_) { + peak_objects_.push_back(object.Copy()); + } + } } -std::unique_ptr HeapEventStorage::ConvertToProto( - ProfileProtoBuilder *builder, - const std::vector> &objects) { +HeapEventStorage::StackTraceArrayBuilder::StackTraceArrayBuilder( + std::size_t objects_size) + : objects_size_(objects_size), + stack_trace_data_( + new google::javaprofiler::ProfileStackTrace[objects_size_]), + call_trace_data_(new JVMPI_CallTrace[objects_size_]) { +} - std::size_t objects_size = objects.size(); +void HeapEventStorage::StackTraceArrayBuilder::AddTrace( + HeapEventStorage::HeapObjectTrace &object) { + std::vector &frames = object.Frames(); - std::unique_ptr stack_trace_data( - new google::javaprofiler::ProfileStackTrace[objects_size]); + call_trace_data_[curr_trace_] = {nullptr, + static_cast(frames.size()), + frames.data()}; - std::unique_ptr call_trace_data( - new JVMPI_CallTrace[objects_size]); + stack_trace_data_[curr_trace_] = {&call_trace_data_[curr_trace_], + object.Size()}; - for (int i = 0; i < objects_size; ++i) { - auto *object = objects[i].get(); - auto *call_target = call_trace_data.get() + i; - auto *trace_target = stack_trace_data.get() + i; + // Add the size as a label to help post-processing filtering. + stack_trace_data_[curr_trace_].trace_and_labels.AddLabel( + "bytes", object.Size(), "bytes"); - auto *frames = object->Frames(); - *call_target = {nullptr, static_cast(frames->size()), frames->data()}; - *trace_target = {call_target, object->Size()}; + curr_trace_++; +} - // Add the size as a label to help post-processing filtering. - trace_target->trace_and_labels.AddLabel("bytes", object->Size(), "bytes"); +std::unique_ptr HeapEventStorage::ConvertToProto( + ProfileProtoBuilder *builder, std::vector &objects) { + StackTraceArrayBuilder stack_trace_builder(objects.size()); + for (int i = 0; i < objects.size(); ++i) { + stack_trace_builder.AddTrace(objects[i]); } - builder->AddTraces(stack_trace_data.get(), objects_size); - + builder->AddTraces(stack_trace_builder.GetStackTraceData(), objects.size()); return builder->CreateProto(); } +std::unique_ptr +HeapEventStorage::GetPeakHeapProfiles(JNIEnv *env, int sampling_interval) { + auto builder = + ProfileProtoBuilder::ForHeap(env, jvmti_, sampling_interval, cache_); + + std::lock_guard lock(storage_lock_); + return ConvertToProto(builder.get(), peak_objects_); +} + std::unique_ptr HeapEventStorage::GetProfiles( JNIEnv *env, int sampling_interval, bool force_gc, bool get_live) { auto builder = @@ -333,6 +369,18 @@ std::unique_ptr HeapMonitor::GetHeapProfiles( return EmptyHeapProfile(env); } +std::unique_ptr HeapMonitor::GetPeakHeapProfiles( + JNIEnv* env, bool force_gc) { +#ifdef ENABLE_HEAP_SAMPLING + // Note: technically this means that you cannot disable the sampler and then + // get the profile afterwards; this could be changed if needed. + if (jvmti_) { + return GetInstance()->storage_.GetPeakHeapProfiles(env, sampling_interval_); + } +#endif + return EmptyHeapProfile(env); +} + std::unique_ptr HeapMonitor::GetGarbageHeapProfiles(JNIEnv* env, bool force_gc) { #ifdef ENABLE_HEAP_SAMPLING diff --git a/third_party/javaprofiler/heap_sampler.h b/third_party/javaprofiler/heap_sampler.h index c65220135..bd830cefe 100644 --- a/third_party/javaprofiler/heap_sampler.h +++ b/third_party/javaprofiler/heap_sampler.h @@ -57,6 +57,10 @@ class HeapEventStorage { return GetProfiles(env, sampling_interval, force_gc, true); } + // Return the largest profile recorded so far. + std::unique_ptr GetPeakHeapProfiles( + JNIEnv *env, int sampling_interval); + // Returns a perftools::profiles::Profile with the objects that have been // GC'd. // force_gc provides a means to force GC before returning the sampled heap @@ -81,11 +85,23 @@ class HeapEventStorage { // 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, - std::unique_ptr> frames) + const std::vector &&frames) : object_(object), size_(size), frames_(std::move(frames)) {} - std::vector *Frames() const { - return frames_.get(); + 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 { @@ -103,41 +119,68 @@ class HeapEventStorage { return !env->IsSameObject(object_, NULL); } - // Not copyable or movable. - HeapObjectTrace(const HeapObjectTrace&) = delete; - HeapObjectTrace& operator=(const HeapObjectTrace&) = delete; + // 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::unique_ptr> frames_; + 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); + + google::javaprofiler::ProfileStackTrace* GetStackTraceData() const { + return stack_trace_data_.get(); + } + + private: + int curr_trace_ = 0; + std::size_t objects_size_; + std::unique_ptr stack_trace_data_; + std::unique_ptr call_trace_data_; }; + static std::unique_ptr ConvertToProto( - ProfileProtoBuilder *builder, - const std::vector> &objects); + ProfileProtoBuilder *builder, std::vector &objects); std::unique_ptr GetProfiles( JNIEnv* env, int sampling_interval, bool force_gc, bool get_live); // Add object to the garbage list: it uses a queue with a max size of // max_garbage_size, provided via the constructor. - void AddToGarbage(std::unique_ptr obj); + // obj will be std::move'd to the garbage_list. + void AddToGarbage(HeapObjectTrace &&obj); // Moves live objects from objects to still_live_objects; live elements from // the objects vector are replaced with nullptr via std::move. void MoveLiveObjects( - JNIEnv *env, std::vector> *objects, - std::vector> *still_live_objects); + JNIEnv *env, std::vector *objects, + std::vector *still_live_objects); + + int64_t ProfileSize(const std::vector &objects) const; - std::vector> newly_allocated_objects_; - std::vector> live_objects_; + std::vector newly_allocated_objects_; + std::vector live_objects_; + + int64_t peak_profile_size_; + std::vector peak_objects_; // Though a queue really would be nice, we need a way to iterate when // requested. int max_garbage_size_; int cur_garbage_pos_; - std::vector> garbage_objects_; + std::vector garbage_objects_; std::mutex storage_lock_; jvmtiEnv *jvmti_; @@ -162,6 +205,10 @@ class HeapMonitor { static std::unique_ptr GetGarbageHeapProfiles( JNIEnv* env, bool force_gc); + // Return the largest profile recorded so far. + static std::unique_ptr GetPeakHeapProfiles( + 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);