Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions tcmalloc/allocation_sample.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "tcmalloc/allocation_sample.h"

#include <cstdint>
#include <memory>
#include <utility>

Expand All @@ -22,6 +23,7 @@
#include "tcmalloc/internal/config.h"
#include "tcmalloc/internal_malloc_extension.h"
#include "tcmalloc/malloc_extension.h"
#include "tcmalloc/parameters.h"
#include "tcmalloc/stack_trace_table.h"

GOOGLE_MALLOC_SECTION_BEGIN
Expand All @@ -31,7 +33,11 @@ AllocationSample::AllocationSample(AllocationSampleList* list, absl::Time start)
: list_(list), start_(start) {
mallocs_ = std::make_unique<StackTraceTable>(ProfileType::kAllocations);
mallocs_->SetStartTime(start_);
list->Add(this);
const int64_t sampling_interval = Parameters::profile_sampling_interval();
mallocs_->SetSamplingInterval(sampling_interval);
if (sampling_interval > 0) {
list->Add(this);
}
}

AllocationSample::~AllocationSample() {
Expand All @@ -40,7 +46,9 @@ AllocationSample::~AllocationSample() {
}

// deleted before ending profile, do it for them
list_->Remove(this);
if (mallocs_->SamplingInterval() > 0) {
list_->Remove(this);
}
}

Profile AllocationSample::Stop() && {
Expand All @@ -49,7 +57,9 @@ Profile AllocationSample::Stop() && {
// A concurrent call to AllocationSampleList::ReportMalloc can access mallocs_
// until we remove it from list_.
if (mallocs_) {
list_->Remove(this);
if (mallocs_->SamplingInterval() > 0) {
list_->Remove(this);
}
mallocs_->SetDuration(absl::Now() - start_);
}
return ProfileAccessor::MakeProfile(std::move(mallocs_));
Expand Down
21 changes: 20 additions & 1 deletion tcmalloc/deallocation_profiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,14 @@ class DeallocationProfiler {
return stop_time_ - start_time_;
}

void SetSamplingInterval(int64_t sampling_interval) {
sampling_interval_ = sampling_interval;
}

std::optional<int64_t> SamplingInterval() const override {
return sampling_interval_;
}

void StopAndRecord(const AllocsTable& allocs);

private:
Expand Down Expand Up @@ -481,6 +489,7 @@ class DeallocationProfiler {

absl::Time start_time_ = absl::Now();
absl::Time stop_time_ = absl::InfiniteFuture();
std::optional<int64_t> sampling_interval_;
};

// Keep track of allocations that are in flight
Expand All @@ -493,6 +502,14 @@ class DeallocationProfiler {
explicit DeallocationProfiler(DeallocationProfilerList* list, Mode mode)
: list_(list), mode_(mode) {
reports_ = std::make_unique<DeallocationStackTraceTable>(mode);
if (mode_ == Mode::kLifetimes) {
const int64_t sampling_interval =
tcmalloc_internal::Parameters::profile_sampling_interval();
reports_->SetSamplingInterval(sampling_interval);
if (sampling_interval <= 0) {
return;
}
}
list_->Add(this);
}

Expand All @@ -506,7 +523,9 @@ class DeallocationProfiler {
if (reports_ != nullptr) {
// We first remove the profiler from the list to avoid racing with
// potential allocations which may modify the allocs_ table.
list_->Remove(this);
if (mode_ != Mode::kLifetimes || reports_->SamplingInterval() > 0) {
list_->Remove(this);
}
reports_->StopAndRecord(allocs_);
return tcmalloc_internal::ProfileAccessor::MakeProfile(
std::move(reports_));
Expand Down
3 changes: 3 additions & 0 deletions tcmalloc/internal/profile_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,9 @@ std::unique_ptr<perftools::profiles::Profile> ProfileBuilder::Finalize() && {
absl::StatusOr<std::unique_ptr<perftools::profiles::Profile>> MakeProfileProto(
const ::tcmalloc::Profile& profile, PageFlagsBase* pageflags,
Residency* residency) {
if (profile.SamplingInterval() == 0) {
return absl::NotFoundError("Profile sampling is disabled");
}
if (profile.Type() == ProfileType::kDoNotUse) {
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
defined(ABSL_HAVE_LEAK_SANITIZER) || \
Expand Down
20 changes: 20 additions & 0 deletions tcmalloc/internal/profile_builder_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,26 @@ TEST(BuildId, ZeroOneAndCorruptAlignment) {
EXPECT_EQ(GetBuildId(&info), "");
}

TEST(ProfileBuilderTest, DisabledSamplingReturnsNotFound) {
class DisabledProfile final : public ProfileBase {
public:
void Iterate(
absl::FunctionRef<void(const Profile::Sample&)>) const override {}
ProfileType Type() const override { return ProfileType::kAllocations; }
std::optional<absl::Time> StartTime() const override {
return std::nullopt;
}
absl::Duration Duration() const override { return absl::ZeroDuration(); }
std::optional<int64_t> SamplingInterval() const override { return 0; }
};

Profile profile =
ProfileAccessor::MakeProfile(std::make_unique<DisabledProfile>());
EXPECT_EQ(profile.SamplingInterval(), 0);
EXPECT_EQ(MakeProfileProto(profile).status().code(),
absl::StatusCode::kNotFound);
}

} // namespace
} // namespace tcmalloc_internal
} // namespace tcmalloc
8 changes: 8 additions & 0 deletions tcmalloc/malloc_extension.cc
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ absl::Duration Profile::Duration() const {
return impl_->Duration();
}

std::optional<int64_t> Profile::SamplingInterval() const {
if (!impl_) {
return std::nullopt;
}

return impl_->SamplingInterval();
}

AddressRegion::~AddressRegion() = default;

size_t AddressRegionFactory::GetStats(absl::Span<char> buffer) {
Expand Down
10 changes: 10 additions & 0 deletions tcmalloc/malloc_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ class Profile final {
// (heap, peakheap, etc.), this returns absl::ZeroDuration().
[[nodiscard]] absl::Duration Duration() const;

// Sampling interval in bytes when the profile was collected, or std::nullopt
// if unspecified. A value of 0 indicates that profile sampling was disabled.
[[nodiscard]] std::optional<int64_t> SamplingInterval() const;

private:
explicit Profile(std::unique_ptr<const tcmalloc_internal::ProfileBase>);

Expand Down Expand Up @@ -923,6 +927,12 @@ class ProfileBase {
// The duration the profile was collected for. For instantaneous profiles
// (heap, peakheap, etc.), this returns absl::ZeroDuration().
[[nodiscard]] virtual absl::Duration Duration() const = 0;

// Sampling interval in bytes when the profile was collected, or std::nullopt
// if unspecified. A value of 0 indicates that profile sampling was disabled.
[[nodiscard]] virtual std::optional<int64_t> SamplingInterval() const {
return std::nullopt;
}
};

enum class MadvisePreference {
Expand Down
11 changes: 11 additions & 0 deletions tcmalloc/stack_trace_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#ifndef TCMALLOC_STACK_TRACE_TABLE_H_
#define TCMALLOC_STACK_TRACE_TABLE_H_

#include <cstdint>
#include <optional>

#include "absl/base/thread_annotations.h"
#include "absl/time/time.h"
#include "tcmalloc/common.h"
Expand Down Expand Up @@ -48,6 +51,13 @@ class StackTraceTable final : public ProfileBase {
void SetDuration(absl::Duration duration) { duration_ = duration; }
[[nodiscard]] absl::Duration Duration() const override { return duration_; }

void SetSamplingInterval(int64_t sampling_interval) {
sampling_interval_ = sampling_interval;
}
[[nodiscard]] std::optional<int64_t> SamplingInterval() const override {
return sampling_interval_;
}

// Adds stack trace "t" of the sample to table with the given weight of the
// sample. `sample_weight` is a floating point value used to calculate the
// the expected number of objects allocated (might be fractional considering
Expand All @@ -68,6 +78,7 @@ class StackTraceTable final : public ProfileBase {
ProfileType type_;
absl::Duration duration_ = absl::ZeroDuration();
absl::Time start_time_;
std::optional<int64_t> sampling_interval_;
int depth_total_;
LinkedSample* all_;
};
Expand Down
Loading