Merge "Implement malloc_info(3)."

This commit is contained in:
Dan Albert 2014-08-22 17:39:18 +00:00 committed by Gerrit Code Review
commit 4756afe3d5
7 changed files with 229 additions and 0 deletions

View File

@ -135,6 +135,7 @@ libc_bionic_src_files := \
bionic/link.cpp \
bionic/locale.cpp \
bionic/lstat.cpp \
bionic/malloc_info.cpp \
bionic/mbrtoc16.cpp \
bionic/mbrtoc32.cpp \
bionic/mbstate.cpp \

View File

@ -16,6 +16,7 @@
#include "dlmalloc.h"
#include "malloc.h"
#include "private/bionic_prctl.h"
#include "private/libc_logging.h"
@ -54,3 +55,25 @@ static void* named_anonymous_mmap(size_t length) {
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, length, "libc_malloc");
return map;
}
// Since dlmalloc isn't the default, we'll leave this unimplemented for now. If
// we decide we need it later, we can fill it in.
size_t __mallinfo_narenas() {
return 0;
}
size_t __mallinfo_nbins() {
return 0;
}
struct mallinfo __mallinfo_arena_info(size_t) {
struct mallinfo mi;
memset(&mi, 0, sizeof(mi));
return mi;
}
struct mallinfo __mallinfo_bin_info(size_t, size_t) {
struct mallinfo mi;
memset(&mi, 0, sizeof(mi));
return mi;
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed 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.
*/
#include "malloc_info.h"
#include <errno.h>
#include "private/bionic_macros.h"
class __LIBC_HIDDEN__ Elem {
public:
// name must be valid throughout lifetime of the object.
explicit Elem(FILE* fp, const char* name,
const char* attr_fmt = nullptr, ...) {
this->fp = fp;
this->name = name;
fprintf(fp, "<%s", name);
if (attr_fmt != nullptr) {
va_list args;
va_start(args, attr_fmt);
fputc(' ', fp);
vfprintf(fp, attr_fmt, args);
va_end(args);
}
fputc('>', fp);
}
~Elem() noexcept {
fprintf(fp, "</%s>", name);
}
void contents(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
}
private:
FILE* fp;
const char* name;
DISALLOW_COPY_AND_ASSIGN(Elem);
};
int malloc_info(int options, FILE* fp) {
if (options != 0) {
errno = EINVAL;
return -1;
}
Elem root(fp, "malloc", "version=\"jemalloc-1\"");
// Dump all of the large allocations in the arenas.
for (size_t i = 0; i < __mallinfo_narenas(); i++) {
struct mallinfo mi = __mallinfo_arena_info(i);
if (mi.hblkhd != 0) {
Elem arena_elem(fp, "heap", "nr=\"%d\"", i);
{
Elem(fp, "allocated-large").contents("%zu", mi.ordblks);
Elem(fp, "allocated-huge").contents("%zu", mi.uordblks);
Elem(fp, "allocated-bins").contents("%zu", mi.fsmblks);
size_t total = 0;
for (size_t j = 0; j < __mallinfo_nbins(); j++) {
struct mallinfo mi = __mallinfo_bin_info(i, j);
if (mi.ordblks != 0) {
Elem bin_elem(fp, "bin", "nr=\"%d\"", j);
Elem(fp, "allocated").contents("%zu", mi.ordblks);
Elem(fp, "nmalloc").contents("%zu", mi.uordblks);
Elem(fp, "ndalloc").contents("%zu", mi.fordblks);
total += mi.ordblks;
}
}
Elem(fp, "bins-total").contents("%zu", total);
}
}
}
return 0;
}

32
libc/bionic/malloc_info.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed 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.
*/
#ifndef LIBC_BIONIC_MALLOC_INFO_H_
#define LIBC_BIONIC_MALLOC_INFO_H_
#include <malloc.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
__LIBC_HIDDEN__ size_t __mallinfo_narenas();
__LIBC_HIDDEN__ size_t __mallinfo_nbins();
__LIBC_HIDDEN__ struct mallinfo __mallinfo_arena_info(size_t);
__LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t);
__END_DECLS
#endif // LIBC_BIONIC_MALLOC_INFO_H_

View File

@ -24,6 +24,7 @@
*/
#include <sys/cdefs.h>
#include <stddef.h>
#include <stdio.h>
__BEGIN_DECLS
@ -53,6 +54,27 @@ struct mallinfo {
extern struct mallinfo mallinfo(void);
/*
* XML structure for malloc_info(3) is in the following format:
*
* <malloc version="jemalloc-1">
* <heap nr="INT">
* <allocated-large>INT</allocated-large>
* <allocated-huge>INT</allocated-huge>
* <allocated-bins>INT</allocated-bins>
* <bins-total>INT</bins-total>
* <bin nr="INT">
* <allocated>INT</allocated>
* <nmalloc>INT</nmalloc>
* <ndalloc>INT</ndalloc>
* </bin>
* <!-- more bins -->
* </heap>
* <!-- more heaps -->
* </malloc>
*/
extern int malloc_info(int, FILE *);
__END_DECLS
#endif /* LIBC_INCLUDE_MALLOC_H_ */

View File

@ -130,6 +130,7 @@ libBionicStandardTests_cppflags := \
libBionicStandardTests_c_includes := \
bionic/libc \
external/tinyxml2 \
libBionicStandardTests_ldlibs_host := \
-lrt \
@ -243,6 +244,10 @@ include $(LOCAL_PATH)/Android.build.mk
bionic-unit-tests_whole_static_libraries := \
libBionicTests \
bionic-unit-tests_static_libraries := \
libtinyxml2 \
liblog \
bionic-unit-tests_src_files := \
atexit_test.cpp \
dlext_test.cpp \
@ -280,6 +285,8 @@ bionic-unit-tests-static_static_libraries := \
libm \
libc \
libstdc++ \
libtinyxml2 \
liblog \
bionic-unit-tests-static_force_static_executable := true

View File

@ -22,6 +22,8 @@
#include <malloc.h>
#include <unistd.h>
#include <tinyxml2.h>
#include "private/bionic_config.h"
TEST(malloc, malloc_std) {
@ -322,3 +324,51 @@ TEST(malloc, valloc_overflow) {
ASSERT_EQ(NULL, valloc(SIZE_MAX));
}
#endif
TEST(malloc, malloc_info) {
#ifdef __BIONIC__
char* buf;
size_t bufsize;
FILE* memstream = open_memstream(&buf, &bufsize);
ASSERT_NE(nullptr, memstream);
ASSERT_EQ(0, malloc_info(0, memstream));
ASSERT_EQ(0, fclose(memstream));
tinyxml2::XMLDocument doc;
ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf));
auto root = doc.FirstChildElement();
ASSERT_NE(nullptr, root);
ASSERT_STREQ("malloc", root->Name());
ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
auto arena = root->FirstChildElement();
for (; arena != nullptr; arena = arena->NextSiblingElement()) {
int val;
ASSERT_STREQ("heap", arena->Name());
ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
arena->FirstChildElement("allocated-large")->QueryIntText(&val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
arena->FirstChildElement("bins-total")->QueryIntText(&val));
auto bin = arena->FirstChildElement("bin");
for (; bin != nullptr; bin = bin ->NextSiblingElement()) {
if (strcmp(bin->Name(), "bin") == 0) {
ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
bin->FirstChildElement("allocated")->QueryIntText(&val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
bin->FirstChildElement("nmalloc")->QueryIntText(&val));
ASSERT_EQ(tinyxml2::XML_SUCCESS,
bin->FirstChildElement("ndalloc")->QueryIntText(&val));
}
}
}
#endif
}