diff mbox

[v3,14/30] perf clang: Support compile IR to BPF object and add testcase

Message ID 20161126070354.141764-15-wangnan0@huawei.com
State Accepted
Commit 5e08a76525b8f5e9aeb8b27d0466614abec070a9
Headers show

Commit Message

Wang Nan Nov. 26, 2016, 7:03 a.m. UTC
getBPFObjectFromModule() is introduced to compile LLVM IR(Module)
to BPF object. Add new testcase for it.

Test result:
  $ ./buildperf/perf test -v clang
  51: Test builtin clang support                               :
  51.1: Test builtin clang compile C source to IR              :
  --- start ---
  test child forked, pid 21822
  test child finished with 0
  ---- end ----
  Test builtin clang support subtest 0: Ok
  51.2: Test builtin clang compile C source to ELF object      :
  --- start ---
  test child forked, pid 21823
  test child finished with 0
  ---- end ----
  Test builtin clang support subtest 1: Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>

Cc: 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: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/tests/clang.c           |  6 ++++-
 tools/perf/util/c++/clang-c.h      |  1 +
 tools/perf/util/c++/clang-test.cpp | 31 +++++++++++++++++++++-----
 tools/perf/util/c++/clang.cpp      | 45 ++++++++++++++++++++++++++++++++++++++
 tools/perf/util/c++/clang.h        |  3 +++
 5 files changed, 79 insertions(+), 7 deletions(-)

-- 
2.10.1

Comments

Alexei Starovoitov Nov. 26, 2016, 5:25 p.m. UTC | #1
On Sat, Nov 26, 2016 at 07:03:38AM +0000, Wang Nan wrote:
> getBPFObjectFromModule() is introduced to compile LLVM IR(Module)

> to BPF object. Add new testcase for it.

> 

> Test result:

>   $ ./buildperf/perf test -v clang

>   51: Test builtin clang support                               :

>   51.1: Test builtin clang compile C source to IR              :

>   --- start ---

>   test child forked, pid 21822

>   test child finished with 0

>   ---- end ----

>   Test builtin clang support subtest 0: Ok

>   51.2: Test builtin clang compile C source to ELF object      :

>   --- start ---

>   test child forked, pid 21823

>   test child finished with 0

>   ---- end ----

>   Test builtin clang support subtest 1: Ok

> 

> Signed-off-by: Wang Nan <wangnan0@huawei.com>

...
> +	legacy::PassManager PM;

> +	if (TargetMachine->addPassesToEmitFile(PM, ostream,

> +					       TargetMachine::CGFT_ObjectFile)) {

> +		llvm::errs() << "TargetMachine can't emit a file of this type\n";

> +		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;

> +	}

> +	PM.run(*Module);


I'm pretty sure you want to add FunctionInlingPass as well otherwise
I think llvm won't be doing much inlining and only very very simple
programs will compile fine. See what we did on bcc side.

Also did you consider skipping elf generation and using in memory
instead ? That will improve compile/run time.
Wang Nan Nov. 28, 2016, 6:32 a.m. UTC | #2
On 2016/11/27 1:25, Alexei Starovoitov wrote:
> On Sat, Nov 26, 2016 at 07:03:38AM +0000, Wang Nan wrote:

>> getBPFObjectFromModule() is introduced to compile LLVM IR(Module)

>> to BPF object. Add new testcase for it.

>>

>> Test result:

>>    $ ./buildperf/perf test -v clang

>>    51: Test builtin clang support                               :

>>    51.1: Test builtin clang compile C source to IR              :

>>    --- start ---

>>    test child forked, pid 21822

>>    test child finished with 0

>>    ---- end ----

>>    Test builtin clang support subtest 0: Ok

>>    51.2: Test builtin clang compile C source to ELF object      :

>>    --- start ---

>>    test child forked, pid 21823

>>    test child finished with 0

>>    ---- end ----

>>    Test builtin clang support subtest 1: Ok

>>

>> Signed-off-by: Wang Nan <wangnan0@huawei.com>

> ...

>> +	legacy::PassManager PM;

>> +	if (TargetMachine->addPassesToEmitFile(PM, ostream,

>> +					       TargetMachine::CGFT_ObjectFile)) {

>> +		llvm::errs() << "TargetMachine can't emit a file of this type\n";

>> +		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;

>> +	}

>> +	PM.run(*Module);

> I'm pretty sure you want to add FunctionInlingPass as well otherwise

> I think llvm won't be doing much inlining and only very very simple

> programs will compile fine. See what we did on bcc side.


Thank you for your information. I though inlining should be done during
C to IR phase, and we have use -O2 for it. Let me check it.

> Also did you consider skipping elf generation and using in memory

> instead ? That will improve compile/run time.

>


Maybe in future work? Current design reuse libelf and bpf-loader for
loading BPF code. Skipping ELF generation make compiling faster, but
require another loader to be coexist with bpf-loader.c, or we need
a new libbpf. In my current experience, outputting ELF is not so slow
for both server and smartphone.

Thank you.
diff mbox

Patch

diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c
index 57ee160..2964c06 100644
--- a/tools/perf/tests/clang.c
+++ b/tools/perf/tests/clang.c
@@ -12,6 +12,10 @@  static struct {
 		.func = test__clang_to_IR,
 		.desc = "Test builtin clang compile C source to IR",
 	},
+	{
+		.func = test__clang_to_obj,
+		.desc = "Test builtin clang compile C source to ELF object",
+	},
 #endif
 };
 
@@ -33,7 +37,7 @@  int test__clang(int i __maybe_unused)
 	return TEST_SKIP;
 }
 #else
-int test__clang(int i __maybe_unused)
+int test__clang(int i)
 {
 	if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table))
 		return TEST_FAIL;
diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
index dcde4b5..22b3936 100644
--- a/tools/perf/util/c++/clang-c.h
+++ b/tools/perf/util/c++/clang-c.h
@@ -9,6 +9,7 @@  extern void perf_clang__init(void);
 extern void perf_clang__cleanup(void);
 
 extern int test__clang_to_IR(void);
+extern int test__clang_to_obj(void);
 
 #ifdef __cplusplus
 }
diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp
index d84e760..9b11e8c 100644
--- a/tools/perf/util/c++/clang-test.cpp
+++ b/tools/perf/util/c++/clang-test.cpp
@@ -13,15 +13,13 @@  public:
 	~perf_clang_scope() {perf_clang__cleanup();}
 };
 
-extern "C" {
-
-int test__clang_to_IR(void)
+static std::unique_ptr<llvm::Module>
+__test__clang_to_IR(void)
 {
-	perf_clang_scope _scope;
 	unsigned int kernel_version;
 
 	if (fetch_kernel_version(&kernel_version, NULL, 0))
-		return -1;
+		return std::unique_ptr<llvm::Module>(nullptr);
 
 	std::string cflag_kver("-DLINUX_VERSION_CODE=" +
 				std::to_string(kernel_version));
@@ -30,14 +28,35 @@  int test__clang_to_IR(void)
 		perf::getModuleFromSource({cflag_kver.c_str()},
 					  "perf-test.c",
 					  test_llvm__bpf_base_prog);
+	return M;
+}
+
+extern "C" {
+int test__clang_to_IR(void)
+{
+	perf_clang_scope _scope;
 
+	auto M = __test__clang_to_IR();
 	if (!M)
 		return -1;
-
 	for (llvm::Function& F : *M)
 		if (F.getName() == "bpf_func__SyS_epoll_wait")
 			return 0;
 	return -1;
 }
 
+int test__clang_to_obj(void)
+{
+	perf_clang_scope _scope;
+
+	auto M = __test__clang_to_IR();
+	if (!M)
+		return -1;
+
+	auto Buffer = perf::getBPFObjectFromModule(&*M);
+	if (!Buffer)
+		return -1;
+	return 0;
+}
+
 }
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
index 715ca0a..2a1a75d 100644
--- a/tools/perf/util/c++/clang.cpp
+++ b/tools/perf/util/c++/clang.cpp
@@ -13,10 +13,15 @@ 
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Option/Option.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
 #include <memory>
 
 #include "clang.h"
@@ -105,12 +110,52 @@  getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
 	return getModuleFromSource(std::move(CFlags), Path, VFS);
 }
 
+std::unique_ptr<llvm::SmallVectorImpl<char>>
+getBPFObjectFromModule(llvm::Module *Module)
+{
+	using namespace llvm;
+
+	std::string TargetTriple("bpf-pc-linux");
+	std::string Error;
+	const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
+	if (!Target) {
+		llvm::errs() << Error;
+		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
+	}
+
+	llvm::TargetOptions Opt;
+	TargetMachine *TargetMachine =
+		Target->createTargetMachine(TargetTriple,
+					    "generic", "",
+					    Opt, Reloc::Static);
+
+	Module->setDataLayout(TargetMachine->createDataLayout());
+	Module->setTargetTriple(TargetTriple);
+
+	std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
+	raw_svector_ostream ostream(*Buffer);
+
+	legacy::PassManager PM;
+	if (TargetMachine->addPassesToEmitFile(PM, ostream,
+					       TargetMachine::CGFT_ObjectFile)) {
+		llvm::errs() << "TargetMachine can't emit a file of this type\n";
+		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;
+	}
+	PM.run(*Module);
+
+	return std::move(Buffer);
+}
+
 }
 
 extern "C" {
 void perf_clang__init(void)
 {
 	perf::LLVMCtx.reset(new llvm::LLVMContext());
+	LLVMInitializeBPFTargetInfo();
+	LLVMInitializeBPFTarget();
+	LLVMInitializeBPFTargetMC();
+	LLVMInitializeBPFAsmPrinter();
 }
 
 void perf_clang__cleanup(void)
diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h
index b4fc2a9..dd8b042 100644
--- a/tools/perf/util/c++/clang.h
+++ b/tools/perf/util/c++/clang.h
@@ -19,5 +19,8 @@  std::unique_ptr<Module>
 getModuleFromSource(opt::ArgStringList CFlags,
 		    StringRef Path);
 
+std::unique_ptr<llvm::SmallVectorImpl<char>>
+getBPFObjectFromModule(llvm::Module *Module);
+
 }
 #endif