From fe0409dd4a7b26a623d2e0ad77be635b20f11d29 Mon Sep 17 00:00:00 2001
Date: Thu, 21 Sep 2023 14:44:51 +0800
Subject:  add 0010-8301749-Tracking-malloc-pooled-memory-size

---
 hotspot/src/os/linux/vm/mallocInfoDcmd.cpp    | 62 +++++++++++++++++++
 hotspot/src/os/linux/vm/mallocInfoDcmd.hpp    | 51 +++++++++++++++
 hotspot/src/os/linux/vm/os_linux.cpp          | 10 +++
 hotspot/src/os/linux/vm/os_linux.hpp          |  4 ++
 .../share/vm/services/diagnosticCommand.cpp   |  2 +
 .../serviceability/dcmd/MallocInfoTest.java   | 54 ++++++++++++++++
 .../com/oracle/java/testlibrary/Platform.java | 18 +++++-
 7 files changed, 199 insertions(+), 2 deletions(-)
 create mode 100644 hotspot/src/os/linux/vm/mallocInfoDcmd.cpp
 create mode 100644 hotspot/src/os/linux/vm/mallocInfoDcmd.hpp
 create mode 100644 hotspot/test/serviceability/dcmd/MallocInfoTest.java

diff --git a/hotspot/src/os/linux/vm/mallocInfoDcmd.cpp b/hotspot/src/os/linux/vm/mallocInfoDcmd.cpp
new file mode 100644
index 000000000..4e50a8e13
--- /dev/null
+++ b/hotspot/src/os/linux/vm/mallocInfoDcmd.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+ 
+#include "precompiled.hpp"
+#include "mallocInfoDcmd.hpp"
+#include "os_linux.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+ 
+#include <malloc.h>
+ 
+const char* malloc_info_unavailable = "Error: malloc_info(3) not available.";
+ 
+void MallocInfoDcmd::execute(DCmdSource source, TRAPS) {
+#ifdef __GLIBC__
+  char* buf;
+  size_t size;
+  FILE* stream = ::open_memstream(&buf, &size);
+  if (stream == NULL) {
+    _output->print_cr("Error: Could not call malloc_info(3)");
+    return;
+  }
+ 
+  int err = os::Linux::malloc_info(stream);
+  if (err == 0) {
+    fflush(stream);
+    _output->print_raw(buf);
+    _output->cr();
+  } else if (err == -1) {
+    _output->print_cr("Error: %s", strerror(errno));
+  } else if (err == -2) {
+    _output->print_cr("%s", malloc_info_unavailable);
+  } else {
+    ShouldNotReachHere();
+  }
+  ::fclose(stream);
+  ::free(buf);
+#else
+  _output->print_cr(malloc_info_unavailable);
+#endif // __GLIBC__
+}
diff --git a/hotspot/src/os/linux/vm/mallocInfoDcmd.hpp b/hotspot/src/os/linux/vm/mallocInfoDcmd.hpp
new file mode 100644
index 000000000..deb154415
--- /dev/null
+++ b/hotspot/src/os/linux/vm/mallocInfoDcmd.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+ 
+#ifndef OS_LINUX_MALLOCINFODCMD_HPP
+#define OS_LINUX_MALLOCINFODCMD_HPP
+ 
+#include "services/diagnosticCommand.hpp"
+ 
+class outputStream;
+ 
+class MallocInfoDcmd : public DCmd {
+public:
+  MallocInfoDcmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+  static const char* name() {
+    return "System.native_heap_info";
+  }
+  static const char* description() {
+    return "Attempts to output information regarding native heap usage through malloc_info(3). If unsuccessful outputs \"Error: \" and a reason.";
+  }
+  static const char* impact() {
+    return "Low";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = { "java.lang.management.ManagementPermission", "monitor", NULL };
+    return p;
+  }
+  void execute(DCmdSource source, TRAPS);
+};
+ 
+#endif // OS_LINUX_MALLOCINFODCMD_HPP
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index cf3a166aa..72839eb5a 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -177,6 +177,8 @@ typedef struct glibc_mallinfo (*mallinfo_func_t)(void);
 typedef struct os::Linux::glibc_mallinfo2 (*mallinfo2_func_t)(void);
 static mallinfo_func_t g_mallinfo = NULL;
 static mallinfo2_func_t g_mallinfo2 = NULL;
+typedef int (*malloc_info_func_t)(int options, FILE *stream);
+static malloc_info_func_t g_malloc_info = NULL;
 #endif // __GLIBC__
 
 static jlong initial_time_count=0;
@@ -5416,6 +5418,7 @@ void os::init(void) {
 #ifdef __GLIBC__
   g_mallinfo = CAST_TO_FN_PTR(mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo"));
   g_mallinfo2 = CAST_TO_FN_PTR(mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2"));
+  g_malloc_info = CAST_TO_FN_PTR(malloc_info_func_t, dlsym(RTLD_DEFAULT, "malloc_info"));
 #endif // __GLIBC__
 
   // _main_thread points to the thread that created/loaded the JVM.
@@ -7072,6 +7075,13 @@ os::Linux::mallinfo_retval_t os::Linux::get_mallinfo(glibc_mallinfo2* out) {
   }
   return os::Linux::ok;
 }
+
+int os::Linux::malloc_info(FILE* stream) {
+  if (g_malloc_info == NULL) {
+    return -2;
+  }
+  return g_malloc_info(0, stream);
+}
 #endif // __GLIBC__
 
 // Trim-native support
diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp
index 39a2b4989..a516335d2 100644
--- a/hotspot/src/os/linux/vm/os_linux.hpp
+++ b/hotspot/src/os/linux/vm/os_linux.hpp
@@ -488,6 +488,10 @@ public:
   // If we only have mallinfo(), values may be 32-bit truncated, which is signaled via
   // "ok_but_possibly_wrapped".
   static mallinfo_retval_t get_mallinfo(glibc_mallinfo2* out);
+  
+  // Calls out to GNU extension malloc_info if available
+  // otherwise does nothing and returns -2.
+  static int malloc_info(FILE* stream);
 #endif
 
   static bool isbound_to_all_node() {
diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp
index 50050a169..416dc77ce 100644
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp
@@ -39,6 +39,7 @@
 
 #ifdef LINUX
 #include "trimCHeapDCmd.hpp"
+#include "mallocInfoDcmd.hpp"
 #endif
 
 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
@@ -79,6 +80,7 @@ void DCmdRegistrant::register_dcmds(){
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
 #ifdef LINUX
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TrimCLibcHeapDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<MallocInfoDcmd>(full_export, true, false));
 #endif // LINUX
 
   // Enhanced JMX Agent Support
diff --git a/hotspot/test/serviceability/dcmd/MallocInfoTest.java b/hotspot/test/serviceability/dcmd/MallocInfoTest.java
new file mode 100644
index 000000000..bc8ab3ef4
--- /dev/null
+++ b/hotspot/test/serviceability/dcmd/MallocInfoTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+ 
+import org.testng.annotations.Test;
+import com.oracle.java.testlibrary.*;
+ 
+/*
+ * @test
+ * @summary Test of diagnostic command System.native_heap_info
+ * @library /testlibrary
+ * @requires (os.family=="linux")
+ * @modules java.base/jdk.internal.misc
+ *          java.compiler
+ *          java.management
+ *          jdk.internal.jvmstat/sun.jvmstat.monitor
+ * @run testng MallocInfoTest
+ */
+public class MallocInfoTest {
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("System.native_heap_info");
+        if (!Platform.isMusl()) {
+            output.shouldNotContain("Error: ");
+            output.shouldContain("<malloc version=");
+        } else {
+            output.shouldContain("Error: malloc_info(3) not available.");
+        }
+        output.reportDiagnosticSummary();
+    }
+ 
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
index 6a1407934..adce2ee35 100644
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
@@ -26,7 +26,8 @@ package com.oracle.java.testlibrary;
 import java.util.regex.Pattern;
 
 import com.oracle.java.testlibrary.Utils;
-
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
 public class Platform {
     private static final String osName      = System.getProperty("os.name");
     private static final String dataModel   = System.getProperty("sun.arch.data.model");
@@ -98,7 +99,20 @@ public class Platform {
     public static String getVMVersion() {
         return vmVersion;
     }
-
+ 
+    public static boolean isMusl() {
+        try {
+            ProcessBuilder pb = new ProcessBuilder("ldd", "--version");
+            pb.redirectErrorStream(true);
+            Process p = pb.start();
+            BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
+            String l = b.readLine();
+            if (l != null && l.contains("musl")) { return true; }
+        } catch(Exception e) {
+        }
+        return false;
+    }
+ 
     // Returns true for sparc and sparcv9.
     public static boolean isSparc() {
         return isArch("sparc.*");
-- 
2.22.0

