Skip to content
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

[MemProf] Expand optimization scope to internal linkage function #73236

Merged
merged 1 commit into from
Dec 1, 2023

Conversation

lifengxiang1025
Copy link
Contributor

Now MemProf can't do IR annotation right in the local linkage function and global initial function __cxx_global_var_init. In llvm-profdata which convert raw memory profile to memory profile, it uses function name in dwarf to create GUID. But when llvm consumes memory profile, it use getIRPGOFuncName or getPGOFuncName which returns local linkage function as FileName;FunctionName or FileName:FunctionName to get function name and create GUID. So profile creator's GUID is not same as profile consumer.
So I think MemProf should be used with unique-internal-linkage-names and don't use PGOFuncName.
__cxx_global_var_init is created later than where UniqueInternalLinkageNames works. So I add uniq suffix to __cxx_global_var_init additionally.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen llvm:transforms labels Nov 23, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 23, 2023

@llvm/pr-subscribers-pgo
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: None (lifengxiang1025)

Changes

Now MemProf can't do IR annotation right in the local linkage function and global initial function __cxx_global_var_init. In llvm-profdata which convert raw memory profile to memory profile, it uses function name in dwarf to create GUID. But when llvm consumes memory profile, it use getIRPGOFuncName or getPGOFuncName which returns local linkage function as FileName;FunctionName or FileName:FunctionName to get function name and create GUID. So profile creator's GUID is not same as profile consumer.
So I think MemProf should be used with unique-internal-linkage-names and don't use PGOFuncName.
__cxx_global_var_init is created later than where UniqueInternalLinkageNames works. So I add uniq suffix to __cxx_global_var_init additionally.


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

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGDeclCXX.cpp (+3)
  • (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+1-15)
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index e08a1e5f42df20c..ae45c23c9e6811c 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -538,6 +538,9 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
   {
     llvm::raw_svector_ostream Out(FnName);
     getCXXABI().getMangleContext().mangleDynamicInitializer(D, Out);
+    if (getCodeGenOpts().UniqueInternalLinkageNames) {
+      Out << getModuleNameHash();
+    }
   }
 
   // Create a variable initialization function.
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index c6134ce77136364..97db0122be7c8e7 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -677,24 +677,10 @@ static void readMemprof(Module &M, Function &F,
                         const TargetLibraryInfo &TLI) {
   auto &Ctx = M.getContext();
 
-  auto FuncName = getIRPGOFuncName(F);
+  auto FuncName = F.getName();
   auto FuncGUID = Function::getGUID(FuncName);
   std::optional<memprof::MemProfRecord> MemProfRec;
   auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
-  if (Err) {
-    // If we don't find getIRPGOFuncName(), try getPGOFuncName() to handle
-    // profiles built by older compilers
-    Err = handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
-      if (IE.get() != instrprof_error::unknown_function)
-        return make_error<InstrProfError>(IE);
-      auto FuncName = getPGOFuncName(F);
-      auto FuncGUID = Function::getGUID(FuncName);
-      if (auto Err =
-              MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec))
-        return Err;
-      return Error::success();
-    });
-  }
   if (Err) {
     handleAllErrors(std::move(Err), [&](const InstrProfError &IPE) {
       auto Err = IPE.get();

@llvmbot
Copy link
Collaborator

llvmbot commented Nov 23, 2023

@llvm/pr-subscribers-llvm-transforms

Author: None (lifengxiang1025)

Changes

Now MemProf can't do IR annotation right in the local linkage function and global initial function __cxx_global_var_init. In llvm-profdata which convert raw memory profile to memory profile, it uses function name in dwarf to create GUID. But when llvm consumes memory profile, it use getIRPGOFuncName or getPGOFuncName which returns local linkage function as FileName;FunctionName or FileName:FunctionName to get function name and create GUID. So profile creator's GUID is not same as profile consumer.
So I think MemProf should be used with unique-internal-linkage-names and don't use PGOFuncName.
__cxx_global_var_init is created later than where UniqueInternalLinkageNames works. So I add uniq suffix to __cxx_global_var_init additionally.


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

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGDeclCXX.cpp (+3)
  • (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+1-15)
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index e08a1e5f42df20c..ae45c23c9e6811c 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -538,6 +538,9 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
   {
     llvm::raw_svector_ostream Out(FnName);
     getCXXABI().getMangleContext().mangleDynamicInitializer(D, Out);
+    if (getCodeGenOpts().UniqueInternalLinkageNames) {
+      Out << getModuleNameHash();
+    }
   }
 
   // Create a variable initialization function.
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index c6134ce77136364..97db0122be7c8e7 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -677,24 +677,10 @@ static void readMemprof(Module &M, Function &F,
                         const TargetLibraryInfo &TLI) {
   auto &Ctx = M.getContext();
 
-  auto FuncName = getIRPGOFuncName(F);
+  auto FuncName = F.getName();
   auto FuncGUID = Function::getGUID(FuncName);
   std::optional<memprof::MemProfRecord> MemProfRec;
   auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
-  if (Err) {
-    // If we don't find getIRPGOFuncName(), try getPGOFuncName() to handle
-    // profiles built by older compilers
-    Err = handleErrors(std::move(Err), [&](const InstrProfError &IE) -> Error {
-      if (IE.get() != instrprof_error::unknown_function)
-        return make_error<InstrProfError>(IE);
-      auto FuncName = getPGOFuncName(F);
-      auto FuncGUID = Function::getGUID(FuncName);
-      if (auto Err =
-              MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec))
-        return Err;
-      return Error::success();
-    });
-  }
   if (Err) {
     handleAllErrors(std::move(Err), [&](const InstrProfError &IPE) {
       auto Err = IPE.get();

@lifengxiang1025
Copy link
Contributor Author

lifengxiang1025 commented Nov 23, 2023

@teresajohnson Can you take a look and provide your insights?

@llvmbot llvmbot added the PGO Profile Guided Optimizations label Nov 27, 2023
@Enna1 Enna1 requested a review from snehasish November 27, 2023 07:31
@teresajohnson
Copy link
Contributor

@snehasish can you take a look at the issue described here? Should we be doing something different in llvm-profdata?

@snehasish
Copy link
Contributor

snehasish commented Nov 27, 2023

@lifengxiang1025 thanks for flagging this issue. I think it's best to not rely on unique-internal-linkage-name here. Instead we should extend the logic in RawMemProfReader.cpp to include "filename;" if the function is internal linkage as expected by IRPGOFuncName. Can you try this approach?

const uint64_t Guid =
IndexedMemProfRecord::getGUID(DIFrame.FunctionName);

@teresajohnson
Copy link
Contributor

@lifengxiang1025 thanks for flagging this issue. I think it's best to not rely on unique-internal-linkage-name here. Instead we should extend the logic in RawMemProfReader.cpp to include "filename;" if the function is internal linkage as expected by IRPGOFuncName. Can you try this approach?

I don't think we want to change the name in the frames themselves, as the names in the debug info when matching don't contain this prefix. Although I suppose we could modify the matcher to add the prefixes when matching frames too. I.e. here:

auto CalleeGUID = Function::getGUID(Name);

It sounds like the issue is that the names used to index the memprof records do not use the PGOFuncName scheme and therefore we never find any memprof records for an internal linkage function during matching. I.e. the GUID passed to InstrProfWriter::addMemProfRecord. Unfortunately, looking at RawMemProfReader.cpp it does look like that eventually gets populated out of the Function (GUID) field from same Frame setup code. So we'd either need to do some extra handling in that code so that the prefix is only used for the record entry, or change the matcher (the latter may be the easiest).

@lifengxiang1025
Copy link
Contributor Author

@lifengxiang1025 thanks for flagging this issue. I think it's best to not rely on unique-internal-linkage-name here. Instead we should extend the logic in RawMemProfReader.cpp to include "filename;" if the function is internal linkage as expected by IRPGOFuncName. Can you try this approach?

const uint64_t Guid =
IndexedMemProfRecord::getGUID(DIFrame.FunctionName);

I don't find how to get linkage type in dwarf. It seems dwarf don't record linkage type. And the linkage type between thin compile and link step can change also.

@snehasish
Copy link
Contributor

change the matcher (the latter may be the easiest).

My response assumed that it was already using the IRPGOFuncName for matching. Yes, I think we should make the switch then.

It seems dwarf don't record linkage type.

Yes, you're right. As an alternative can we use the symbol table and find Bind = LOCAL to add the prefix before hashing?

@lifengxiang1025
Copy link
Contributor Author

lifengxiang1025 commented Nov 29, 2023

Yes, you're right. As an alternative can we use the symbol table and find Bind = LOCAL to add the prefix before hashing?

If we choose this method. I think we can't deal with the situation which one symbol is not local linkage type in thin compile, but will be converted to local linkage after thin backend by thinlto's internalization. In this situation function name in llvm-profdata will have prefix with file name. But when llvm consumes memory profile, PGOFuncName won't return function name with prefix.

@teresajohnson
Copy link
Contributor

Yes, you're right. As an alternative can we use the symbol table and find Bind = LOCAL to add the prefix before hashing?

If we choose this method. I think we can't deal with the situation which one symbol is not local linkage type in thin compile, but will be converted to local linkage after thin backend by thinlto's internalization. In this situation function name in llvm-profdata will have prefix with file name. But when llvm consumes memory profile, PGOFuncName won't return function name with prefix.

If I understand the issue you are describing, that would only occur if the instrumentation build also used ThinLTO. Is that a typical use case for you?

@teresajohnson
Copy link
Contributor

@snehasish and I chatted more about this offline. Using the dwarf info to figure out the right source name prefix during indexing is not straightforward. The source file name used as the prefix in the compiler for the IRPGOName is that of the TU. The source file of the line in the dwarf info may be a header. It could be possible to walk up the profiled inline frames to find a source file, but that is error prone in certain circumstances (e.g. if the profiled binary had thinlto cross module inlining, and if it isn't obvious which source file name is a non-included TU).

I think your change to the matching is almost strictly better than the complete non-matching we get currently for local functions. It would even work in many cases without uniq suffixes, but uniq suffixes will make that work even better. So let's go ahead with that change.

However, we'd like to request that you split the __cxx_global_var_init change into a separate patch, as it is somewhat orthogonal to the matching change, and in case there are unexpected issues with that change. Can you split that out and make the test case here for matching of a non __cxx_global_var_init function?

Thanks!

@lifengxiang1025 lifengxiang1025 force-pushed the lfx.memprof branch 2 times, most recently from f91e72a to 3e50c55 Compare November 30, 2023 06:40
@lifengxiang1025
Copy link
Contributor Author

@snehasish and I chatted more about this offline. Using the dwarf info to figure out the right source name prefix during indexing is not straightforward. The source file name used as the prefix in the compiler for the IRPGOName is that of the TU. The source file of the line in the dwarf info may be a header. It could be possible to walk up the profiled inline frames to find a source file, but that is error prone in certain circumstances (e.g. if the profiled binary had thinlto cross module inlining, and if it isn't obvious which source file name is a non-included TU).

I think your change to the matching is almost strictly better than the complete non-matching we get currently for local functions. It would even work in many cases without uniq suffixes, but uniq suffixes will make that work even better. So let's go ahead with that change.

However, we'd like to request that you split the __cxx_global_var_init change into a separate patch, as it is somewhat orthogonal to the matching change, and in case there are unexpected issues with that change. Can you split that out and make the test case here for matching of a non __cxx_global_var_init function?

Thanks!

Thanks for your reply. I have removed the __cxx_global_var_init change. Please review again.

@Enna1
Copy link
Contributor

Enna1 commented Dec 1, 2023

also s/linakge/linkage/ in commit message and PR title.

@lifengxiang1025 lifengxiang1025 changed the title [MemProf] Expand optimization scope to internal linakge function [MemProf] Expand optimization scope to internal linkage function Dec 1, 2023
@Enna1 Enna1 merged commit 340cb19 into llvm:main Dec 1, 2023
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang Clang issues not falling into any other category llvm:transforms PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants