Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf clang: Add builtin clang support ant test case

Add basic clang support in clang.cpp and test__clang() testcase. The
first testcase checks if builtin clang is able to generate LLVM IR.

tests/clang.c is a proxy. Real testcase resides in
utils/c++/clang-test.cpp in c++ and exports C interface to perf test
subsystem.

Test result:

$ perf test -v clang
51: builtin clang support :
51.1: Test builtin clang compile C source to IR :
--- start ---
test child forked, pid 13215
test child finished with 0
---- end ----
Test builtin clang support subtest 0: Ok

Committer note:

Make sure you've enabled CLANG and LLVM builtin support by setting
the LIBCLANGLLVM variable on the make command line, e.g.:

make LIBCLANGLLVM=1 O=/tmp/build/perf -C tools/perf install-bin

Otherwise you'll get this when trying to do the 'perf test' call above:

# perf test clang
51: builtin clang support : Skip (not compiled in)
#

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Joe Stringer <joe@ovn.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/20161126070354.141764-11-wangnan0@huawei.com
[ Removed "Test" from descriptions, redundant and already removed from all the other entries ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
00b86691 d58ac0bf

+218
+1
tools/perf/tests/Build
··· 43 43 perf-y += is_printable_array.o 44 44 perf-y += bitmap.o 45 45 perf-y += perf-hooks.o 46 + perf-y += clang.o 46 47 47 48 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build 48 49 $(call rule_mkdir)
+9
tools/perf/tests/builtin-test.c
··· 234 234 .func = test__perf_hooks, 235 235 }, 236 236 { 237 + .desc = "builtin clang support", 238 + .func = test__clang, 239 + .subtest = { 240 + .skip_if_fail = true, 241 + .get_nr = test__clang_subtest_get_nr, 242 + .get_desc = test__clang_subtest_get_desc, 243 + } 244 + }, 245 + { 237 246 .func = NULL, 238 247 }, 239 248 };
+42
tools/perf/tests/clang.c
··· 1 + #include "tests.h" 2 + #include "debug.h" 3 + #include "util.h" 4 + #include "c++/clang-c.h" 5 + 6 + static struct { 7 + int (*func)(void); 8 + const char *desc; 9 + } clang_testcase_table[] = { 10 + #ifdef HAVE_LIBCLANGLLVM_SUPPORT 11 + { 12 + .func = test__clang_to_IR, 13 + .desc = "builtin clang compile C source to IR", 14 + }, 15 + #endif 16 + }; 17 + 18 + int test__clang_subtest_get_nr(void) 19 + { 20 + return (int)ARRAY_SIZE(clang_testcase_table); 21 + } 22 + 23 + const char *test__clang_subtest_get_desc(int i) 24 + { 25 + if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table)) 26 + return NULL; 27 + return clang_testcase_table[i].desc; 28 + } 29 + 30 + #ifndef HAVE_LIBCLANGLLVM_SUPPORT 31 + int test__clang(int i __maybe_unused) 32 + { 33 + return TEST_SKIP; 34 + } 35 + #else 36 + int test__clang(int i __maybe_unused) 37 + { 38 + if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table)) 39 + return TEST_FAIL; 40 + return clang_testcase_table[i].func(); 41 + } 42 + #endif
+3
tools/perf/tests/tests.h
··· 92 92 int test__is_printable_array(int subtest); 93 93 int test__bitmap_print(int subtest); 94 94 int test__perf_hooks(int subtest); 95 + int test__clang(int subtest); 96 + const char *test__clang_subtest_get_desc(int subtest); 97 + int test__clang_subtest_get_nr(void); 95 98 96 99 #if defined(__arm__) || defined(__aarch64__) 97 100 #ifdef HAVE_DWARF_UNWIND_SUPPORT
+2
tools/perf/util/Build
··· 126 126 127 127 libperf-y += perf-hooks.o 128 128 129 + libperf-$(CONFIG_CXX) += c++/ 130 + 129 131 CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 130 132 # avoid compiler warnings in 32-bit mode 131 133 CFLAGS_genelf_debug.o += -Wno-packed
+2
tools/perf/util/c++/Build
··· 1 + libperf-$(CONFIG_CLANGLLVM) += clang.o 2 + libperf-$(CONFIG_CLANGLLVM) += clang-test.o
+16
tools/perf/util/c++/clang-c.h
··· 1 + #ifndef PERF_UTIL_CLANG_C_H 2 + #define PERF_UTIL_CLANG_C_H 3 + 4 + #ifdef __cplusplus 5 + extern "C" { 6 + #endif 7 + 8 + extern void perf_clang__init(void); 9 + extern void perf_clang__cleanup(void); 10 + 11 + extern int test__clang_to_IR(void); 12 + 13 + #ifdef __cplusplus 14 + } 15 + #endif 16 + #endif
+31
tools/perf/util/c++/clang-test.cpp
··· 1 + #include "clang.h" 2 + #include "clang-c.h" 3 + #include "llvm/IR/Function.h" 4 + #include "llvm/IR/LLVMContext.h" 5 + 6 + class perf_clang_scope { 7 + public: 8 + explicit perf_clang_scope() {perf_clang__init();} 9 + ~perf_clang_scope() {perf_clang__cleanup();} 10 + }; 11 + 12 + extern "C" { 13 + 14 + int test__clang_to_IR(void) 15 + { 16 + perf_clang_scope _scope; 17 + 18 + std::unique_ptr<llvm::Module> M = 19 + perf::getModuleFromSource("perf-test.c", 20 + "int myfunc(void) {return 1;}"); 21 + 22 + if (!M) 23 + return -1; 24 + 25 + for (llvm::Function& F : *M) 26 + if (F.getName() == "myfunc") 27 + return 0; 28 + return -1; 29 + } 30 + 31 + }
+96
tools/perf/util/c++/clang.cpp
··· 1 + /* 2 + * llvm C frontend for perf. Support dynamically compile C file 3 + * 4 + * Inspired by clang example code: 5 + * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp 6 + * 7 + * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com> 8 + * Copyright (C) 2016 Huawei Inc. 9 + */ 10 + 11 + #include "clang/CodeGen/CodeGenAction.h" 12 + #include "clang/Frontend/CompilerInvocation.h" 13 + #include "clang/Frontend/CompilerInstance.h" 14 + #include "clang/Frontend/TextDiagnosticPrinter.h" 15 + #include "clang/Tooling/Tooling.h" 16 + #include "llvm/IR/Module.h" 17 + #include "llvm/Option/Option.h" 18 + #include "llvm/Support/ManagedStatic.h" 19 + #include <memory> 20 + 21 + #include "clang.h" 22 + #include "clang-c.h" 23 + 24 + namespace perf { 25 + 26 + static std::unique_ptr<llvm::LLVMContext> LLVMCtx; 27 + 28 + using namespace clang; 29 + 30 + static vfs::InMemoryFileSystem * 31 + buildVFS(StringRef& Name, StringRef& Content) 32 + { 33 + vfs::InMemoryFileSystem *VFS = new vfs::InMemoryFileSystem(true); 34 + VFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content)); 35 + return VFS; 36 + } 37 + 38 + static CompilerInvocation * 39 + createCompilerInvocation(StringRef& Path, DiagnosticsEngine& Diags) 40 + { 41 + llvm::opt::ArgStringList CCArgs { 42 + "-cc1", 43 + "-triple", "bpf-pc-linux", 44 + "-fsyntax-only", 45 + "-ferror-limit", "19", 46 + "-fmessage-length", "127", 47 + "-O2", 48 + "-nostdsysteminc", 49 + "-nobuiltininc", 50 + "-vectorize-loops", 51 + "-vectorize-slp", 52 + "-Wno-unused-value", 53 + "-Wno-pointer-sign", 54 + "-x", "c"}; 55 + CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs); 56 + 57 + FrontendOptions& Opts = CI->getFrontendOpts(); 58 + Opts.Inputs.clear(); 59 + Opts.Inputs.emplace_back(Path, IK_C); 60 + return CI; 61 + } 62 + 63 + std::unique_ptr<llvm::Module> 64 + getModuleFromSource(StringRef Name, StringRef Content) 65 + { 66 + CompilerInstance Clang; 67 + Clang.createDiagnostics(); 68 + 69 + IntrusiveRefCntPtr<vfs::FileSystem> VFS = buildVFS(Name, Content); 70 + Clang.setVirtualFileSystem(&*VFS); 71 + 72 + IntrusiveRefCntPtr<CompilerInvocation> CI = 73 + createCompilerInvocation(Name, Clang.getDiagnostics()); 74 + Clang.setInvocation(&*CI); 75 + 76 + std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); 77 + if (!Clang.ExecuteAction(*Act)) 78 + return std::unique_ptr<llvm::Module>(nullptr); 79 + 80 + return Act->takeModule(); 81 + } 82 + 83 + } 84 + 85 + extern "C" { 86 + void perf_clang__init(void) 87 + { 88 + perf::LLVMCtx.reset(new llvm::LLVMContext()); 89 + } 90 + 91 + void perf_clang__cleanup(void) 92 + { 93 + perf::LLVMCtx.reset(nullptr); 94 + llvm::llvm_shutdown(); 95 + } 96 + }
+16
tools/perf/util/c++/clang.h
··· 1 + #ifndef PERF_UTIL_CLANG_H 2 + #define PERF_UTIL_CLANG_H 3 + 4 + #include "llvm/ADT/StringRef.h" 5 + #include "llvm/IR/LLVMContext.h" 6 + #include "llvm/IR/Module.h" 7 + #include <memory> 8 + namespace perf { 9 + 10 + using namespace llvm; 11 + 12 + std::unique_ptr<Module> 13 + getModuleFromSource(StringRef Name, StringRef Content); 14 + 15 + } 16 + #endif