Skip to content

[MemProf] Add interface for reseting the profile file descriptor #73714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 29, 2023

Conversation

teresajohnson
Copy link
Contributor

Add __memprof_profile_reset() interface which can be used to facilitate
dumping multiple rounds of profiles from a single binary run. This
closes the current file descriptor and resets the internal file
descriptor to invalid (-1), which ensures the underlying writer reopens
the recorded profile filename. This can be used once the client is done
moving or copying a dumped profile, to prepare for reinvoking profile
dumping.

Add __memprof_profile_reset() interface which can be used to facilitate
dumping multiple rounds of profiles from a single binary run. This
closes the current file descriptor and resets the internal file
descriptor to invalid (-1), which ensures the underlying writer reopens
the recorded profile filename. This can be used once the client is done
moving or copying a dumped profile, to prepare for reinvoking profile
dumping.
@llvmbot llvmbot added compiler-rt PGO Profile Guided Optimizations labels Nov 28, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 28, 2023

@llvm/pr-subscribers-pgo

Author: Teresa Johnson (teresajohnson)

Changes

Add __memprof_profile_reset() interface which can be used to facilitate
dumping multiple rounds of profiles from a single binary run. This
closes the current file descriptor and resets the internal file
descriptor to invalid (-1), which ensures the underlying writer reopens
the recorded profile filename. This can be used once the client is done
moving or copying a dumped profile, to prepare for reinvoking profile
dumping.


Full diff: https://github.com/llvm/llvm-project/pull/73714.diff

4 Files Affected:

  • (modified) compiler-rt/include/sanitizer/memprof_interface.h (+6)
  • (modified) compiler-rt/lib/memprof/memprof_allocator.cpp (+8)
  • (modified) compiler-rt/lib/memprof/memprof_interface_internal.h (+1)
  • (added) compiler-rt/test/memprof/TestCases/profile_reset.cpp (+39)
diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h
index fe0a2fc5ef025bf..4660a7818c92b3c 100644
--- a/compiler-rt/include/sanitizer/memprof_interface.h
+++ b/compiler-rt/include/sanitizer/memprof_interface.h
@@ -59,6 +59,12 @@ const char *SANITIZER_CDECL __memprof_default_options(void);
 /// \returns 0 on success.
 int SANITIZER_CDECL __memprof_profile_dump(void);
 
+/// Closes the existing file descriptor, if it is valid and not stdout or
+/// stderr, and resets the internal state such that the profile filename is
+/// reopened on the next profile dump attempt. This can be used to enable
+/// multiple rounds of profiling on the same binary.
+void SANITIZER_CDECL __memprof_profile_reset(void);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
index efdfa5ad04a6917..12890fae101c3e7 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -738,3 +738,11 @@ int __memprof_profile_dump() {
   // detected during the dumping process.
   return 0;
 }
+
+void __memprof_profile_reset() {
+  if (report_file.fd != kInvalidFd && report_file.fd != kStdoutFd &&
+      report_file.fd != kStderrFd) {
+    CloseFile(report_file.fd);
+    report_file.fd = kInvalidFd;
+  }
+}
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 0aca4afc9afa9b7..318bc410440562f 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -49,6 +49,7 @@ extern uptr __memprof_shadow_memory_dynamic_address;
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
     __memprof_profile_filename[1];
 SANITIZER_INTERFACE_ATTRIBUTE int __memprof_profile_dump();
+SANITIZER_INTERFACE_ATTRIBUTE void __memprof_profile_reset();
 
 SANITIZER_INTERFACE_ATTRIBUTE void __memprof_load(uptr p);
 SANITIZER_INTERFACE_ATTRIBUTE void __memprof_store(uptr p);
diff --git a/compiler-rt/test/memprof/TestCases/profile_reset.cpp b/compiler-rt/test/memprof/TestCases/profile_reset.cpp
new file mode 100644
index 000000000000000..0130722eb2cf624
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/profile_reset.cpp
@@ -0,0 +1,39 @@
+// Test to ensure that multiple rounds of dumping, using the
+// __memprof_profile_reset interface to close the initial file
+// and cause the profile to be reopened, works as expected.
+
+// RUN: %clangxx_memprof  %s -o %t
+
+// RUN: rm -f %t.log.*
+// RUN: %env_memprof_opts=print_text=true:log_path=%t.log %run %t
+
+// Check both outputs, starting with the renamed initial dump, then remove it so
+// that the second glob matches a single file.
+// RUN: FileCheck %s --dump-input=always < %t.log.*.sv
+// RUN: rm -f %t.log.*.sv
+// RUN: FileCheck %s --dump-input=always < %t.log.*
+// CHECK: Memory allocation stack id
+
+#include <sanitizer/memprof_interface.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+int main(int argc, char **argv) {
+  char *x = (char *)malloc(10);
+  memset(x, 0, 10);
+  free(x);
+  __memprof_profile_dump();
+  // Save the initial dump in a different file.
+  std::string origname = __sanitizer_get_report_path();
+  std::string svname = origname + ".sv";
+  rename(origname.c_str(), svname.c_str());
+  // This should cause the current file descriptor to be closed and the
+  // the internal state reset so that the profile filename is reopened
+  // on the next write.
+  __memprof_profile_reset();
+  // This will dump to origname again.
+  __memprof_profile_dump();
+  return 0;
+}

Copy link
Contributor

@snehasish snehasish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm


// Check both outputs, starting with the renamed initial dump, then remove it so
// that the second glob matches a single file.
// RUN: FileCheck %s --dump-input=always < %t.log.*.sv
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the dump-input left over from debugging? The default is on fail which seems fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this came in when I copied from another test, where it is presumably leftover debugging. I removed from here.

if (report_file.fd != kInvalidFd && report_file.fd != kStdoutFd &&
report_file.fd != kStderrFd) {
CloseFile(report_file.fd);
report_file.fd = kInvalidFd;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment why we need to set this to kInvalidFd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@teresajohnson teresajohnson merged commit ae86239 into llvm:main Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-rt PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants