blob: a31d92e1a06bb09066f476faabc442a1ac5b854d [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <string>
#include <glog/logging.h>
#include "common/status.h"
#include "util/metrics-fwd.h"
namespace impala {
class MallocUtil {
public:
// Gets the MallocUtil singleton. Always a non-nullptr.
static MallocUtil* GetInstance();
// Initialize the settings for the malloc implementation. This should be called once
// at startup. Since backend tests may call this repeatedly, any additional calls
// are ignored.
virtual Status Init(int64_t process_memory_limit) = 0;
// Malloc implementations that retain extra memory usually provide a way to manually
// free excess memory. This should try to free the specified amount of excess
// memory.
virtual void ReleaseMemoryToSystem(int64_t bytes_to_free) {}
// Gets a human readable description of malloc state / statistics
virtual std::string GetTextDescription() const = 0;
// The name of the malloc implementation
virtual std::string GetName() const = 0;
// Add malloc implementation specific metrics in the provided metrics group.
virtual Status RegisterMemoryMetrics(MetricGroup* metrics) = 0;
// Get the metric for used memory. This can only be called after initialization.
// This must be non-null for all malloc implementations.
virtual IntGauge* GetUsedBytesMetric(bool include_overhead) const = 0;
// Get the metric for the malloc implementation's overhead. This can only be
// called after initialization. This will return null if the malloc
// implementation does not have an overhead metric.
virtual IntGauge* GetOverheadBytesMetric() const = 0;
// Get information about the malloc implementation's support for huge pages.
// MADVISE_COMPATIBLE - It is permissible to use madvise() with MADV_HUGEPAGE
// on properly aligned large buffers to use huge pages. The malloc
// implementation does not split them up or decommit them in smaller chunks.
// A malloc implementation that immediately frees memory (e.g. Gperftools
// TCMalloc's aggressive decommit mode) can guarantee this.
// MADVISE_INCOMPATIBLE - The malloc implementation can't guarantee that it
// will operate properly with huge pages. It may break up huge pages. This
// is true for most malloc implementations that retain memory without
// explicit huge page support.
// MADVISE_UNNECESSARY - The malloc implementation uses huge pages natively.
// Callers should not use madvise() with MADV_HUGEPAGE themselves, because
// the malloc implementation is already doing this. If the malloc implementation
// retains memory, it does so in a way that is aware of huge pages.
// This can only be called after initialization.
enum class HugePageSupport {
MADVISE_COMPATIBLE,
MADVISE_INCOMPATIBLE,
MADVISE_UNNECESSARY
};
virtual HugePageSupport GetHugePageSupport() const = 0;
friend std::ostream& operator<<(std::ostream& os, const HugePageSupport& h);
// Profiler interfaces
// This will need to evolve as other malloc implementations are added. Right now,
// this only needs to handle Gperftools TCMalloc and the sanitizers. To simplify
// implementations that don't support profiling, these default to returning false
// and DCHECKing if any are used.
//
// Currently, all the different types of profiling return a binary structure for
// use with the pprof utility. These are the current types of profiling:
// Heap profiling: profile all allocations for a period of time. The call pattern
// is HeapProfilerStart(), wait for some samples to be collected,
// GetHeapProfile(), then HeapProfilerStop().
// Heap growth stacks: return stacks for allocations that caused the address space
// to grow.
// CPU profiling: send a signal and sample stacks. The call pattern is
// CPUProfileStart(), wait for some samples to be collected, then
// CPUProfileStop(). This writes the profile to a temporary file that can be
// read back.
virtual bool SupportsHeapProfiling() const { return false; }
virtual void HeapProfilerStart(const std::string& tmp_prof_file_name) {
DCHECK(false);
}
virtual void HeapProfilerStop() { DCHECK(false); }
// Returns a binary heap profile. The returned pointer is a '\0'-terminated
// string allocated using malloc() and should be free()-ed as soon as the
// caller does not need it anymore.
virtual char* GetHeapProfile() {
DCHECK(false);
return nullptr;
}
virtual bool SupportsHeapGrowthStacks() const {
return false;
}
virtual void GetHeapGrowthStacks(std::string* heap_growth_stacks) {
DCHECK(false);
}
virtual bool SupportsCPUProfiling() const { return false; }
virtual void CPUProfilerStart(const std::string& tmp_prof_file_name) {
DCHECK(false);
}
virtual void CPUProfilerStop() {
DCHECK(false);
}
protected:
// Restrict access to the constructor / destructor to protect the singleton.
MallocUtil() = default;
~MallocUtil() = default;
private:
DISALLOW_COPY_AND_ASSIGN(MallocUtil);
};
} // namespace impala