Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -208,6 +208,7 @@ #================================ include(CheckIncludeFile) check_include_file(unwind.h HAVE_UNWIND_H) +check_include_file(mpi.h HAVE_MPI_H) include(config-ix) Index: lib/profile/CMakeLists.txt =================================================================== --- lib/profile/CMakeLists.txt +++ lib/profile/CMakeLists.txt @@ -36,6 +36,7 @@ InstrProfilingPlatformDarwin.c InstrProfilingPlatformLinux.c InstrProfilingPlatformOther.c + InstrProfilingMPI.c InstrProfilingRuntime.cc InstrProfilingUtil.c) @@ -55,6 +56,12 @@ -DCOMPILER_RT_HAS_ATOMICS=1) endif() +if(HAVE_MPI_H) + set(EXTRA_FLAGS + ${EXTRA_FLAGS} + -DHAVE_MPI_H=1) +endif() + if(APPLE) add_compiler_rt_runtime(clang_rt.profile STATIC Index: lib/profile/InstrProfiling.h =================================================================== --- lib/profile/InstrProfiling.h +++ lib/profile/InstrProfiling.h @@ -13,6 +13,8 @@ #include "InstrProfilingPort.h" #include "InstrProfData.inc" +COMPILER_RT_VISIBILITY extern int __llvm_write_prof_data; + enum ValueKind { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, #include "InstrProfData.inc" Index: lib/profile/InstrProfilingFile.c =================================================================== --- lib/profile/InstrProfilingFile.c +++ lib/profile/InstrProfilingFile.c @@ -14,6 +14,15 @@ #include #include #include +#include +#include + +#ifdef _MSC_VER +#include +#include +#else +#include +#endif #define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) @@ -72,7 +81,6 @@ static void truncateCurrentFile(void) { const char *Filename; - FILE *File; Filename = __llvm_profile_CurrentFilename; if (!Filename || !Filename[0]) @@ -86,11 +94,16 @@ free(Copy); } - /* Truncate the file. Later we'll reopen and append. */ - File = fopen(Filename, "w"); - if (!File) + /* truncate, or open without O_CREAT, is used to avoid creating empty files. + * In MPI applications, a file will only be created by one process */ +#ifdef _MSC_VER + int File = _open(Filename, _O_WRONLY | _O_TRUNC); + if (File == -1) return; - fclose(File); + _close(File); +#else + (void) truncate(Filename, 0); +#endif } static void setFilename(const char *Filename, int OwnsFilename) { @@ -215,7 +228,10 @@ } COMPILER_RT_VISIBILITY -int __llvm_profile_write_file(void) { +int __llvm_profile_write_file(void) { + if (!__llvm_write_prof_data) + return 0; + int rc; GetEnvHook = &getenv; Index: lib/profile/InstrProfilingMPI.c =================================================================== --- /dev/null +++ lib/profile/InstrProfilingMPI.c @@ -0,0 +1,50 @@ +/*===-- InstrProfilingMPI.c - Support library for applications using MPI --===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +\*===----------------------------------------------------------------------===*/ + +#include +#include +#ifdef HAVE_MPI_H +#include +#endif + +/* Defined here to make sure that the linker brings in the MPI_Finalize + * definition provided in this file */ +COMPILER_RT_VISIBILITY int __llvm_write_prof_data = 1; + +COMPILER_RT_WEAK int PMPI_Finalize() { abort(); } + +#ifdef HAVE_MPI_H +COMPILER_RT_VISIBILITY int MPI_Finalize() { + int Rank; + uint64_t *CountersBegin = __llvm_profile_begin_counters(); + uint64_t *CountersEnd = __llvm_profile_end_counters(); + uint64_t CountersSize = CountersEnd - CountersBegin; + + PMPI_Comm_rank(MPI_COMM_WORLD, &Rank); + + /* Only counters are reduced here, not value profile data */ + if (Rank) { + PMPI_Reduce(CountersBegin, NULL, CountersSize, MPI_UINT64_T, MPI_SUM, + 0, MPI_COMM_WORLD); + __llvm_write_prof_data = 0; + } else { + PMPI_Reduce(MPI_IN_PLACE, CountersBegin, CountersSize, MPI_UINT64_T, + MPI_SUM, 0, MPI_COMM_WORLD); + } + return PMPI_Finalize(); +} + +COMPILER_RT_WEAK int PMPI_Comm_rank(MPI_Comm comm, int *rank) { abort(); } +COMPILER_RT_WEAK int PMPI_Reduce(const void *sendbuf, void *recvbuf, int count, + MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) { abort(); } +#else +/* Included here so regression test has a definition to use */ +COMPILER_RT_WEAK int MPI_Finalize() { return PMPI_Finalize(); } +#endif + Index: test/profile/instrprof-reduce.c =================================================================== --- /dev/null +++ test/profile/instrprof-reduce.c @@ -0,0 +1,23 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: rm -f %t.profraw +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t 0 +// RUN: test -e %t.profraw +// RUN: rm -f %t.profraw +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t 1 +// RUN: test ! -e %t.profraw +// REQUIRES: shell + +#include +#include +int ThisRank; +int PMPI_Comm_rank(void *Comm, int *Rank) { *Rank = ThisRank; return 0; } +int PMPI_Reduce() { return 0; } +int PMPI_Finalize() { return 0; } +int MPI_Finalize(); + +int main(int argc, const char *argv[]) { + ThisRank = atoi(argv[1]); + MPI_Finalize(); + return 0; +} +