我在源文件中包含一组标头,这些标头很少/从未更改。解析/重新解析使用标头的频繁更改的源文件(IDE 用例)需要太长时间(几秒钟)。作为提高性能的一种方式,我想使用 Clang PCH。请注意,我正在 Android 上以发布模式(99% 确定)编译 libclang(不是最新版本)。
我已经按照回答类似的问题 https://stackoverflow.com/a/20952634/1103561但与标头解析相比,PCH 的性能差 3 倍(使用具有 100000 个的人工标头)#define
宏):
2020-08-11 12:03:53.265 19767-19788 W/TranslationUnitTest: PCH parse time: 0.462277
2020-08-11 12:03:53.265 19767-19788 W/TranslationUnitTest: 0 diagnostics
2020-08-11 12:03:55.768 19767-19788 W/TranslationUnitTest: Source parse time: 1.456947
2020-08-11 12:03:55.768 19767-19788 W/TranslationUnitTest: 0 diagnostics
Java源代码(在Android Instrumentation测试中运行):
final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
// create PCH
dir = new File(context.getCacheDir(), String.valueOf(Math.abs(new Random().nextLong())));
dir.mkdirs();
deeperHeaderFile = new File(dir, "deeperHeader.h");
StringBuilder sb = new StringBuilder("#define VAL 1 ");
for (int i=0; i<100000; i++) {
sb.append("\n");
sb.append("#define VAL" + i + " " + i);
}
setFileContent(deeperHeaderFile, sb.toString());
headerFile = new File(dir, "header.hxx");
setFileContent(headerFile, "#include \"deeperHeader.h\"");
pchFile = new File(dir, "header.pch");
sourceFile = new File(dir, "source.cpp");
setFileContent(sourceFile, "#include \"header.hxx\"\nint main() { return VAL; }");
// C++ test
Clang.testPch(
pchFile.getAbsolutePath(),
headerFile.getAbsolutePath(),
deeperHeaderFile.getAbsolutePath(),
sourceFile.getAbsolutePath());
C++源代码:
class Timer {
public:
Timer () {
reset();
}
double get () {
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_sec - start_.tv_sec + 1e-6 * (now.tv_usec - start_.tv_usec);
}
void reset () {
gettimeofday (&start_, NULL);
}
private:
struct timeval start_;
};
void displayDiagnostics(CXTranslationUnit TU) {
if (TU == 0) {
std::cerr << "Parsing error!" << std::endl;
return;
}
int numDiagnostics = clang_getNumDiagnostics (TU);
__android_log_print(ANDROID_LOG_WARN, TAG, "%d diagnostics", numDiagnostics);
for (int i=0 ; i<numDiagnostics ; ++i) {
auto diagnostic = clang_getDiagnostic(TU, i);
auto string = clang_formatDiagnostic(diagnostic, clang_defaultDiagnosticDisplayOptions());
auto cString = clang_getCString(string);
__android_log_print(ANDROID_LOG_WARN, TAG, "diag #%d: %s", i, cString);
clang_disposeString(string);
clang_disposeDiagnostic(diagnostic);
}
}
JNIEXPORT void JNICALL Clang_testPch(
JNIEnv *env, jclass clazz,
jstring jPchFilename, jstring jHeaderFilename, jstring jDeeperHeaderFilename, jstring jSourceFilename) {
char *cPchFilename = string_copy(env, jPchFilename);
char *cHeaderFilename = string_copy(env, jHeaderFilename);
char *cDeeperHeaderFilename = string_copy(env, jDeeperHeaderFilename);
char *cSourceFilename = string_copy(env, jSourceFilename);
auto Idx = clang_createIndex (0, 0);
CXTranslationUnit TU;
Timer t;
{
char const *args[] = { "-xc++", cHeaderFilename };
int nargs = 2;
t.reset();
TU = clang_parseTranslationUnit(Idx, 0, args, nargs, 0, 0, CXTranslationUnit_ForSerialization);
auto pchParsetime = t.get();
__android_log_print(ANDROID_LOG_WARN, TAG, "PCH parse time: %f", pchParsetime);
displayDiagnostics(TU);
clang_saveTranslationUnit(TU, cPchFilename, clang_defaultSaveOptions(TU));
clang_disposeTranslationUnit(TU);
}
{
char const *args[] = { "-include-pch", cPchFilename, cSourceFilename };
int nargs = 3;
t.reset();
TU = clang_createTranslationUnitFromSourceFile(Idx, 0, nargs, args, 0, 0);
auto parseTime = t.get();
__android_log_print(ANDROID_LOG_WARN, TAG, "Source parse time: %f", parseTime);
displayDiagnostics(TU);
clang_disposeTranslationUnit(TU);
}
// release
delete []cPchFilename;
delete []cHeaderFilename;
delete []cDeeperHeaderFilename;
delete []cSourceFilename;
}
我相信文件是用 Java 编写的并没有什么区别(最初的原因是我有 clang 绑定并且 Java 代码具有相同的[坏]性能,所以我更改了要在 C++ 中测试的代码)。
我错过了什么吗?有什么愚蠢的错误吗?有什么建议么?