This update incorporates: - Documentation fix to clarify that directories are created at runtime. - Allow -fprofile-generate and -fprofile-instr-generate to have the usual last-wins semantics. - Move __llvm_profile_recursive_mkdir into its own file in the runtime library.
OK to commit? Thanks. Diego.
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index cd1b2b3..20ee569 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -1488,6 +1488,45 @@ instrumentation: profile. As you make changes to your code, clang may no longer be able to use the profile data. It will warn you when this happens. +Profile generation and use can also be controlled by the GCC-compatible flags +``-fprofile-generate`` and ``-fprofile-use``. Although these flags are +semantically equivalent to their GCC counterparts, they *do not* handle +GCC-compatible profiles. They are only meant to implement GCC's semantics +with respect to profile creation and use. + +.. option:: -fprofile-generate[=<dirname>] + + Without any other arguments, ``-fprofile-generate`` behaves identically to + ``-fprofile-instr-generate``. When given a directory name, it generates the + profile file ``default.profraw`` in the directory named ``dirname``. If + ``dirname`` does not exist, it will be created at runtime. The environment + variable ``LLVM_PROFILE_FILE`` can be used to override the directory and + filename for the profile file at runtime. For example, + + .. code-block:: console + + $ clang++ -O2 -fprofile-generate=yyy/zzz code.cc -o code + + When ``code`` is executed, the profile will be written to the file + ``yyy/zzz/default.profraw``. This can be altered at runtime via the + ``LLVM_PROFILE_FILE`` environment variable: + + .. code-block:: console + + $ LLVM_PROFILE_FILE=/tmp/myprofile/code.profraw ./code + + The above invocation will produce the profile file + ``/tmp/myprofile/code.profraw`` instead of ``yyy/zzz/default.profraw``. + Notice that ``LLVM_PROFILE_FILE`` overrides the directory *and* the file + name for the profile file. + +.. option:: -fprofile-use[=<pathname>] + + Without any other arguments, ``-fprofile-use`` behaves identically to + ``-fprofile-instr-use``. Otherwise, if ``pathname`` is the full path to a + profile file, it reads from that file. If ``pathname`` is a directory name, + it reads from ``pathname/default.profdata``. + Controlling Size of Debug Information ------------------------------------- diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index df90371..1202724 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -422,13 +422,24 @@ def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">, Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<file>">, HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">; -def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>; +def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>, + Flags<[DriverOption]>; def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use instrumentation data for profile-guided optimization">; def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Generate coverage mapping to enable code coverage analysis">; +def fprofile_generate : Flag<["-"], "fprofile-generate">, + Alias<fprofile_instr_generate>; +def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">, + HelpText<"Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">; +def fprofile_use : Flag<["-"], "fprofile-use">, Group<f_Group>, + Alias<fprofile_instr_use>; +def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, + Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<pathname>">, + HelpText<"Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profile. Otherwise, it reads from file <pathname>.">; def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable the 'blocks' language feature">; @@ -904,7 +915,6 @@ def fpie : Flag<["-"], "fpie">, Group<f_Group>; def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>; def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>; def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>; -def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>; def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>; def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, Flags<[CC1Option]>, @@ -1794,8 +1804,6 @@ defm : BooleanFFlag<"keep-inline-functions">, Group<clang_ignored_gcc_optimizati def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>; -defm profile_use : BooleanFFlag<"profile-use">, Group<clang_ignored_gcc_optimization_f_Group>; -def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group<clang_ignored_gcc_optimization_f_Group>; def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>; defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>; diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index 66597bd..53246bc 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -155,6 +155,7 @@ public: std::vector<std::string> DependentLibraries; /// Name of the profile file to use as output for -fprofile-instr-generate + /// and -fprofile-generate. std::string InstrProfileOutput; /// Name of the profile file to use with -fprofile-sample-use. diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 463503b..fd70868 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -303,6 +303,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 1795ccf..ee70793 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -2298,6 +2298,7 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || @@ -3533,22 +3534,34 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); if ((Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ)) && + Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || + Args.hasArg(options::OPT_fprofile_generate_EQ)) && (Args.hasArg(options::OPT_fprofile_instr_use) || - Args.hasArg(options::OPT_fprofile_instr_use_EQ))) + Args.hasArg(options::OPT_fprofile_instr_use_EQ) || + Args.hasArg(options::OPT_fprofile_use_EQ))) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fprofile-instr-generate" << "-fprofile-instr-use"; if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_generate_EQ)) A->render(Args, CmdArgs); - else + else if (Arg *A = Args.getLastArg(options::OPT_fprofile_generate_EQ)) { + SmallString<128> Path(A->getValue()); + llvm::sys::path::append(Path, "default.profraw"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); + } else Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ)) A->render(Args, CmdArgs); - else if (Args.hasArg(options::OPT_fprofile_instr_use)) - CmdArgs.push_back("-fprofile-instr-use=pgo-data"); + else if (Arg *A = Args.getLastArg(options::OPT_fprofile_use_EQ, + options::OPT_fprofile_instr_use)) { + SmallString<128> Path(A->getNumValues() == 0 ? "" : A->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + } if (Args.hasArg(options::OPT_ftest_coverage) || Args.hasArg(options::OPT_coverage)) @@ -3560,7 +3573,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fcoverage_mapping) && !(Args.hasArg(options::OPT_fprofile_instr_generate) || - Args.hasArg(options::OPT_fprofile_instr_generate_EQ))) + Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || + Args.hasArg(options::OPT_fprofile_generate_EQ))) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fcoverage-mapping" << "-fprofile-instr-generate"; diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index 68890a7..74cdf5b 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -66,6 +66,40 @@ // CHECK-PROFILE-ARCS: "-femit-coverage-data" // CHECK-NO-PROFILE-ARCS-NOT: "-femit-coverage-data" +// RUN: %clang -### -S -fprofile-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s +// RUN: %clang -### -S -fprofile-instr-generate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s +// RUN: %clang -### -S -fprofile-generate=/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-DIR %s +// RUN: %clang -### -S -fprofile-instr-generate=/tmp/somefile.profraw %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE-FILE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-instr-generate=file -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-use=dir %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// RUN: %clang -### -S -fprofile-generate=dir -fprofile-instr-use=file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s +// CHECK-PROFILE-GENERATE: "-fprofile-instr-generate" +// CHECK-PROFILE-GENERATE-DIR: "-fprofile-instr-generate=/some/dir/default.profraw" +// CHECK-PROFILE-GENERATE-FILE: "-fprofile-instr-generate=/tmp/somefile.profraw" +// CHECK-NO-MIX-GEN-USE: '-fprofile-instr-generate' not allowed with '-fprofile-instr-use' + +// RUN: %clang -### -S -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s +// RUN: %clang -### -S -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s +// RUN: mkdir -p %t.d/some/dir +// RUN: %clang -### -S -fprofile-use=%t.d/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-DIR %s +// RUN: %clang -### -S -fprofile-instr-use=/tmp/somefile.prof %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// CHECK-PROFILE-USE: "-fprofile-instr-use=default.profdata" +// CHECK-PROFILE-USE-DIR: "-fprofile-instr-use={{.*}}.d/some/dir/default.profdata" +// CHECK-PROFILE-USE-FILE: "-fprofile-instr-use=/tmp/somefile.prof" + // RUN: %clang -### -S -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s // RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s // RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s @@ -162,7 +196,6 @@ // RUN: -fprefetch-loop-arrays -fno-prefetch-loop-arrays \ // RUN: -fprofile-correction -fno-profile-correction \ // RUN: -fprofile-dir=bar \ -// RUN: -fprofile-use -fprofile-use=zed -fno-profile-use \ // RUN: -fprofile-values -fno-profile-values \ // RUN: -frounding-math -fno-rounding-math \ // RUN: -fsee -fno-see \ @@ -242,8 +275,6 @@ // RUN: -fno-keep-inline-functions \ // RUN: -freorder-blocks \ // RUN: -fprofile-dir=/rand/dir \ -// RUN: -fprofile-use \ -// RUN: -fprofile-use=/rand/dir \ // RUN: -falign-functions \ // RUN: -falign-functions=1 \ // RUN: -ffloat-store \ @@ -312,8 +343,6 @@ // CHECK-WARNING-DAG: optimization flag '-fno-keep-inline-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported // CHECK-WARNING-DAG: optimization flag '-fprofile-dir=/rand/dir' is not supported -// CHECK-WARNING-DAG: optimization flag '-fprofile-use' is not supported -// CHECK-WARNING-DAG: optimization flag '-fprofile-use=/rand/dir' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-falign-functions=1' is not supported // CHECK-WARNING-DAG: optimization flag '-ffloat-store' is not supported diff --git a/test/Profile/Inputs/gcc-flag-compatibility.proftext b/test/Profile/Inputs/gcc-flag-compatibility.proftext new file mode 100644 index 0000000..99d41bb --- /dev/null +++ b/test/Profile/Inputs/gcc-flag-compatibility.proftext @@ -0,0 +1,5 @@ +main +4 +2 +1 +100 diff --git a/test/Profile/gcc-flag-compatibility.c b/test/Profile/gcc-flag-compatibility.c new file mode 100644 index 0000000..53a7651 --- /dev/null +++ b/test/Profile/gcc-flag-compatibility.c @@ -0,0 +1,48 @@ +// Tests for -fprofile-generate and -fprofile-use flag compatibility. These two +// flags behave similarly to their GCC counterparts: +// +// -fprofile-generate Generates the profile file ./default.profraw +// -fprofile-generate=<dir> Generates the profile file <dir>/default.profraw +// -fprofile-use Uses the profile file ./default.profdata +// -fprofile-use=<dir> Uses the profile file <dir>/default.profdata +// -fprofile-use=<dir>/file Uses the profile file <dir>/file + +// Check that -fprofile-generate uses the runtime default profile file. +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate | FileCheck -check-prefix=PROFILE-GEN %s +// PROFILE-GEN: @__llvm_profile_runtime = external global i32 +// PROFILE-GEN-NOT: call void @__llvm_profile_override_default_filename +// PROFILE-GEN-NOT: declare void @__llvm_profile_override_default_filename(i8*) + +// Check that -fprofile-generate=/path/to generates /path/to/default.profraw +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to | FileCheck -check-prefix=PROFILE-GEN-EQ %s +// PROFILE-GEN-EQ: private constant [25 x i8] c"/path/to/default.profraw\00" +// PROFILE-GEN-EQ: call void @__llvm_profile_override_default_filename(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @0, i32 0, i32 0)) +// PROFILE-GEN-EQ: declare void @__llvm_profile_override_default_filename(i8*) + +// Check that -fprofile-use reads default.profdata +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o default.profdata +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-use | FileCheck -check-prefix=PROFILE-USE-1 %s +// PROFILE-USE-1: = !{!"branch_weights", i32 101, i32 2} + +// Check that -fprofile-use=some/path reads some/path/default.profdata +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/default.profdata +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-use=%t.dir/some/path | FileCheck -check-prefix=PROFILE-USE-2 %s +// PROFILE-USE-2: = !{!"branch_weights", i32 101, i32 2} + +// Check that -fprofile-use=some/path/file.prof reads some/path/file.prof +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/file.prof +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof | FileCheck -check-prefix=PROFILE-USE-3 %s +// PROFILE-USE-3: = !{!"branch_weights", i32 101, i32 2} + +int X = 0; + +int main() { + int i; + for (i = 0; i < 100; i++) + X += i; + return 0; +}
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt index d0714e0..d03409f 100644 --- a/lib/profile/CMakeLists.txt +++ b/lib/profile/CMakeLists.txt @@ -7,7 +7,8 @@ set(PROFILE_SOURCES InstrProfilingFile.c InstrProfilingPlatformDarwin.c InstrProfilingPlatformOther.c - InstrProfilingRuntime.cc) + InstrProfilingRuntime.cc + InstrProfilingUtil.c) if(APPLE) add_compiler_rt_osx_static_runtime(clang_rt.profile_osx diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index e32e97f..aec2328 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -20,6 +20,8 @@ |* \*===----------------------------------------------------------------------===*/ +#include "InstrProfilingUtil.h" + #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -27,17 +29,9 @@ #include <string.h> #include <sys/mman.h> #include <sys/file.h> -#ifdef _WIN32 -#include <direct.h> -#endif #define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) -#if !I386_FREEBSD -#include <sys/stat.h> -#include <sys/types.h> -#endif - #if !defined(_MSC_VER) && !I386_FREEBSD #include <stdint.h> #endif @@ -52,7 +46,6 @@ typedef unsigned long long uint64_t; typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; -int mkdir(const char*, unsigned short); #endif /* #define DEBUG_GCDAPROFILING */ @@ -209,21 +202,6 @@ static char *mangle_filename(const char *orig_filename) { return new_filename; } -static void recursive_mkdir(char *path) { - int i; - - for (i = 1; path[i] != '\0'; ++i) { - if (path[i] != '/') continue; - path[i] = '\0'; -#ifdef _WIN32 - _mkdir(path); -#else - mkdir(path, 0755); /* Some of these will fail, ignore it. */ -#endif - path[i] = '/'; - } -} - static int map_file() { fseek(output_file, 0L, SEEK_END); file_size = ftell(output_file); @@ -283,7 +261,7 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4], fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Try creating the directories first then opening the file. */ - recursive_mkdir(filename); + __llvm_profile_recursive_mkdir(filename); fd = open(filename, O_RDWR | O_CREAT, 0644); if (fd == -1) { /* Bah! It's hopeless. */ diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h index 84b673c..3778a88 100644 --- a/lib/profile/InstrProfiling.h +++ b/lib/profile/InstrProfiling.h @@ -64,7 +64,7 @@ uint64_t *__llvm_profile_end_counters(void); * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, * or if that's not set, the last name given to * \a __llvm_profile_override_default_filename(), or if that's not set, - * \c "default.profdata". + * \c "default.profraw". */ int __llvm_profile_write_file(void); diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index 0102a25..9402238 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -8,6 +8,7 @@ \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" +#include "InstrProfilingUtil.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -84,6 +85,13 @@ static void truncateCurrentFile(void) { if (!Filename || !Filename[0]) return; + /* Create the directory holding the file, if needed. */ + if (strchr(Filename, '/')) { + char *Copy = malloc(strlen(Filename) + 1); + strcpy(Copy, Filename); + __llvm_profile_recursive_mkdir(Copy); + } + /* Truncate the file. Later we'll reopen and append. */ File = fopen(Filename, "w"); if (!File) diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c new file mode 100644 index 0000000..e146dfc --- /dev/null +++ b/lib/profile/InstrProfilingUtil.c @@ -0,0 +1,35 @@ +/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +\*===----------------------------------------------------------------------===*/ + +#include "InstrProfilingUtil.h" + +#ifdef _WIN32 +#include <direct.h> +#elif I386_FREEBSD +int mkdir(const char*, unsigned short); +#else +#include <sys/stat.h> +#include <sys/types.h> +#endif + +__attribute__((visibility("hidden"))) +void __llvm_profile_recursive_mkdir(char *path) { + int i; + + for (i = 1; path[i] != '\0'; ++i) { + if (path[i] != '/') continue; + path[i] = '\0'; +#ifdef _WIN32 + _mkdir(path); +#else + mkdir(path, 0755); /* Some of these will fail, ignore it. */ +#endif + path[i] = '/'; + } +} diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h new file mode 100644 index 0000000..756b18e --- /dev/null +++ b/lib/profile/InstrProfilingUtil.h @@ -0,0 +1,16 @@ +/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +\*===----------------------------------------------------------------------===*/ + +#ifndef PROFILE_INSTRPROFILINGUTIL_H +#define PROFILE_INSTRPROFILINGUTIL_H + +/*! \brief Create a directory tree. */ +void __llvm_profile_recursive_mkdir(char *Pathname); + +#endif /* PROFILE_INSTRPROFILINGUTIL_H */ diff --git a/test/profile/Inputs/gcc-flag-compatibility.c b/test/profile/Inputs/gcc-flag-compatibility.c new file mode 100644 index 0000000..1c07bb1 --- /dev/null +++ b/test/profile/Inputs/gcc-flag-compatibility.c @@ -0,0 +1,8 @@ +int X = 0; + +int main() { + int i; + for (i = 0; i < 100; i++) + X += i; + return 0; +} diff --git a/test/profile/gcc-flag-compatibility.test b/test/profile/gcc-flag-compatibility.test new file mode 100644 index 0000000..8e8b55d --- /dev/null +++ b/test/profile/gcc-flag-compatibility.test @@ -0,0 +1,17 @@ +RUN: mkdir -p %t.d +RUN: %clang_profgen_gcc=%t.d/d1/d2 -o %t.d/code %S/Inputs/gcc-flag-compatibility.c + +# Test that the instrumented code writes to %t.d/d1/d2/default.profraw +RUN: %run %t.d/code +RUN: llvm-profdata merge -o %t.profdata %t.d/d1/d2/default.profraw + +# Test that we can override the directory and file name with LLVM_PROFILE_FILE. +RUN: env LLVM_PROFILE_FILE=%t.d/x1/prof.raw %run %t.d/code +RUN: llvm-profdata merge -o %t.profdata %t.d/x1/prof.raw + +# Test that we can specify a directory with -fprofile-use. +RUN: llvm-profdata merge -o %t.d/default.profdata %t.d/x1/prof.raw +RUN: %clang_profuse_gcc=%t.d -o %t.d/code %S/Inputs/gcc-flag-compatibility.c + +# Test that we can specify a file with -fprofile-use. +RUN: %clang_profuse_gcc=%t.profdata -o %t.d/code %S/Inputs/gcc-flag-compatibility.c diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index e4910ab..b1b44a1 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -45,6 +45,8 @@ def build_invocation(compile_flags): config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) config.substitutions.append( ("%clang_profgen ", build_invocation(clang_cflags) + " -fprofile-instr-generate ") ) config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") ) +config.substitutions.append( ("%clang_profgen_gcc=", build_invocation(clang_cflags) + " -fprofile-generate=") ) +config.substitutions.append( ("%clang_profuse_gcc=", build_invocation(clang_cflags) + " -fprofile-use=") ) if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: config.unsupported = True
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits