From 5f6f50107b3ca95419207190340490894f15f99c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 7 Apr 2002 15:20:53 +0200 Subject: [PATCH] avoid a 2nd cpp run by compiling the pre-processed output on a cache miss this lowers the overhead in the case of a cache miss to just about zero! --- ccache.1 | 21 ++++++++++ ccache.c | 94 +++++++++++++++++++++++++++++++++++++-------- ccache.h | 2 +- ccache.yo | 19 +++++++++ web/ccache-man.html | 17 ++++++++ 5 files changed, 135 insertions(+), 18 deletions(-) diff --git a/ccache.1 b/ccache.1 index eacc9735c..8ee4b1c48 100644 --- a/ccache.1 +++ b/ccache.1 @@ -134,6 +134,16 @@ If you set the environment variable CCACHE_DISABLE then ccache will just call the real compiler, bypassing the cache completely\&. .IP +.IP "\fBCCACHE_CPP2\fP" +If you set the environment variable CCACHE_CPP2 +then ccache will not use the optimisation of avoiding the 2nd call to +the pre-processor by compiling the pre-processed output that was used +for finding the hash in the case of a cache miss\&. This is primarily a +debugging option, although it is possible that some unusual compilers +will have problems with the intermediate filename extensions used in +this optimisation, in which case this option could allow ccache to be +used\&. +.IP .IP "\fBCCACHE_NOSTATS\fP" If you set the environment variable CCACHE_NOSTATS then ccache will not update the statistics files on @@ -250,6 +260,17 @@ compiling rsync I get: .fi +.PP +.SH "CREDITS" +.PP +Thanks to the following people for their contributions to ccache +.IP o +Erik Thiele for the original compilercache script +.IP o +Luciano Rocha for the idea of compiling the pre-processor output +to avoid a 2nd cpp pass +.IP o +Paul Russell for many suggestions and the debian packaging .PP .SH "AUTHOR" .PP diff --git a/ccache.c b/ccache.c index 6f50cac7f..94559aba6 100644 --- a/ccache.c +++ b/ccache.c @@ -22,21 +22,68 @@ #include "ccache.h" +/* the base cache directory */ char *cache_dir = NULL; + +/* the debug logfile name, if set */ char *cache_logfile = NULL; + +/* the argument list after processing */ static ARGS *stripped_args; + +/* the original argument list */ static ARGS *orig_args; + +/* the output filename being compiled to */ static char *output_file; + +/* the source file */ static char *input_file; + +/* the name of the file containing the cached object code */ static char *hashname; + +/* the extension of the file after pre-processing */ +static char *i_extension; + +/* the name of the temporary pre-processor file */ +static char *i_tmpfile; + +/* the name of the statistics file */ char *stats_file = NULL; + +/* did we find a -g option? */ static int found_debug; +/* a list of supported file extensions, and the equivalent + extension for code that has been through the pre-processor +*/ +static struct { + char *extension; + char *i_extension; +} extensions[] = { + {"c", "i"}, + {"C", "ii"}, + {"m", "mi"}, + {"cc", "ii"}, + {"CC", "ii"}, + {"cpp", "ii"}, + {"CPP", "ii"}, + {"cxx", "ii"}, + {"CXX", "ii"}, + {NULL, NULL}}; + /* something went badly wrong - just execute the real compiler */ static void failed(void) { + /* delete intermediate pre-processor file if needed */ + if (i_tmpfile) { + unlink(i_tmpfile); + free(i_tmpfile); + i_tmpfile = NULL; + } execv(orig_args->argv[0], orig_args->argv); cc_log("execv returned (%s)!\n", strerror(errno)); perror(orig_args->argv[0]); @@ -57,8 +104,14 @@ static void to_cache(ARGS *args) args_add(args, "-o"); args_add(args, tmp_hashname); + + if (getenv("CCACHE_CPP2")) { + args_add(args, input_file); + } else { + args_add(args, i_tmpfile); + } status = execute(args->argv, tmp_stdout, tmp_stderr); - args_pop(args, 2); + args_pop(args, 3); if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) { cc_log("compiler produced stdout for %s\n", output_file); @@ -136,9 +189,6 @@ static void find_hash(ARGS *args) theory is that these arguments will change the output of -E if they are going to have any effect at all, or they only affect linking */ - if (strcmp(args->argv[i], input_file) == 0) { - continue; - } if (i < args->argc-1) { if (strcmp(args->argv[i], "-I") == 0 || strcmp(args->argv[i], "-include") == 0 || @@ -169,12 +219,14 @@ static void find_hash(ARGS *args) hash_int(st.st_mtime); /* now the run */ - x_asprintf(&path_stdout, "%s/tmp.stdout.%d", cache_dir, getpid()); + x_asprintf(&path_stdout, "%s/tmp.stdout.%d.%s", cache_dir, getpid(), + i_extension); x_asprintf(&path_stderr, "%s/tmp.stderr.%d", cache_dir, getpid()); args_add(args, "-E"); + args_add(args, input_file); status = execute(args->argv, path_stdout, path_stderr); - args_pop(args, 1); + args_pop(args, 2); if (status != 0) { unlink(path_stdout); @@ -198,9 +250,8 @@ static void find_hash(ARGS *args) } hash_file(path_stderr); - unlink(path_stdout); + i_tmpfile = path_stdout; unlink(path_stderr); - free(path_stdout); free(path_stderr); /* we use a N level subdir for the cache path to reduce the impact @@ -288,6 +339,13 @@ static void from_cache(int first) utime(output_file, NULL); } + /* get rid of the intermediate preprocessor file */ + if (i_tmpfile) { + unlink(i_tmpfile); + free(i_tmpfile); + i_tmpfile = NULL; + } + /* send the stderr */ copy_fd(fd_stderr, 2); close(fd_stderr); @@ -383,20 +441,22 @@ static void find_compiler(int argc, char **argv) } -/* check a filename for C/C++ extension */ -static int check_extension(const char *fname) +/* check a filename for C/C++ extension. Return the pre-processor + extension */ +static char *check_extension(const char *fname) { - char *extensions[] = {"c", "C", "m", "cc", "CC", "cpp", "CPP", "cxx", "CXX", 0}; int i; char *p; p = strrchr(fname, '.'); - if (!p) return -1; + if (!p) return NULL; p++; - for (i=0; extensions[i]; i++) { - if (strcmp(p, extensions[i]) == 0) return 0; + for (i=0; extensions[i].extension; i++) { + if (strcmp(p, extensions[i].extension) == 0) { + return extensions[i].i_extension; + } } - return -1; + return NULL; } @@ -499,7 +559,6 @@ static void process_args(int argc, char **argv) } input_file = argv[i]; - args_add(stripped_args, argv[i]); } if (!input_file) { @@ -508,7 +567,8 @@ static void process_args(int argc, char **argv) failed(); } - if (check_extension(input_file) != 0) { + i_extension = check_extension(input_file); + if (i_extension == NULL) { cc_log("Not a C/C++ file - %s\n", input_file); stats_update(STATS_NOTC); failed(); diff --git a/ccache.h b/ccache.h index 347ab3660..b4b4c8451 100644 --- a/ccache.h +++ b/ccache.h @@ -1,4 +1,4 @@ -#define CCACHE_VERSION "1.5" +#define CCACHE_VERSION "1.6" #include "config.h" diff --git a/ccache.yo b/ccache.yo index 547d0cf45..e7a884a00 100644 --- a/ccache.yo +++ b/ccache.yo @@ -114,6 +114,15 @@ dit(bf(CCACHE_DISABLE)) If you set the environment variable CCACHE_DISABLE then ccache will just call the real compiler, bypassing the cache completely. +dit(bf(CCACHE_CPP2)) If you set the environment variable CCACHE_CPP2 +then ccache will not use the optimisation of avoiding the 2nd call to +the pre-processor by compiling the pre-processed output that was used +for finding the hash in the case of a cache miss. This is primarily a +debugging option, although it is possible that some unusual compilers +will have problems with the intermediate filename extensions used in +this optimisation, in which case this option could allow ccache to be +used. + dit(bf(CCACHE_NOSTATS)) If you set the environment variable CCACHE_NOSTATS then ccache will not update the statistics files on each compile. @@ -216,6 +225,16 @@ verb( ccache cached 4.6 seconds ) +manpagesection(CREDITS) + +Thanks to the following people for their contributions to ccache +itemize( + it() Erik Thiele for the original compilercache script + it() Luciano Rocha for the idea of compiling the pre-processor output + to avoid a 2nd cpp pass + it() Paul Russell for many suggestions and the debian packaging +) + manpageauthor() ccache was written by Andrew Tridgell diff --git a/web/ccache-man.html b/web/ccache-man.html index 63e46b41f..ab31883bd 100644 --- a/web/ccache-man.html +++ b/web/ccache-man.html @@ -113,6 +113,14 @@ ccache itself.

CCACHE_DISABLE
If you set the environment variable CCACHE_DISABLE then ccache will just call the real compiler, bypassing the cache completely. +

CCACHE_CPP2
If you set the environment variable CCACHE_CPP2 +then ccache will not use the optimisation of avoiding the 2nd call to +the pre-processor by compiling the pre-processed output that was used +for finding the hash in the case of a cache miss. This is primarily a +debugging option, although it is possible that some unusual compilers +will have problems with the intermediate filename extensions used in +this optimisation, in which case this option could allow ccache to be +used.

CCACHE_NOSTATS
If you set the environment variable CCACHE_NOSTATS then ccache will not update the statistics files on each compile. @@ -202,6 +210,15 @@ compiling rsync I get: +

CREDITS

+ +

Thanks to the following people for their contributions to ccache +

AUTHOR

ccache was written by Andrew Tridgell -- 2.47.2