commit 683ec2c97c1c74fda6402ebc2aaa51367960caa1
parent 509b9b5121a02df42717f13ba77861c136fe8a25
Author: Kyle Milz <kyle@getaddrinfo.net>
Date: Thu, 7 Apr 2016 22:54:12 -0600
src: fundamentally rework how instrumentation works
- the per translation unit book keeping struct is now named after the source
file name, and not a monotonically increasing number
- this has advantages, namely objects compiled in different directories can be
combined without symbol name collisions
- don't rely on ELF common symbols for the whole scheme to work
- these common symbols allow multiple definitions in different translation
units to be linked together successfully
- unfortunately this is a fortran-compatible feature and C++ _never_ emits
common symbols
- instead use symbol chaining and abuse the --defsym linker arg
- --defsym allows the entry point in the runtime library to be bound to the
last link in the instrumented translation unit chain
- also rename stuff from _scv_* to _citrun_*
Diffstat:
16 files changed, 126 insertions(+), 108 deletions(-)
diff --git a/SCV/Project.pm b/SCV/Project.pm
@@ -46,8 +46,8 @@ EOF
syswrite( $jamfile_fh, $jamfile );
close( $jamfile_fh );
+ # Use the tools in this source tree
my $cwd = getcwd;
-
$ENV{CITRUN_PATH} = "$cwd/share";
$ENV{PATH} = "$ENV{CITRUN_PATH}:$ENV{PATH}";
@@ -61,7 +61,7 @@ sub instrumented_src {
open( my $inst_fh, "<", "$self->{tmp_dir}/inst/source_0.c" );
# Knock off the instrumentation preamble
- my $line = <$inst_fh> for (1..25);
+ my $line = <$inst_fh> for (1..26);
my $inst_src;
while (my $line = <$inst_fh>) {
@@ -77,7 +77,7 @@ sub inst_src_preamble {
open( my $inst_fh, "<", "$self->{tmp_dir}/inst/source_0.c" );
my $preamble;
- for (1..25) {
+ for (1..26) {
my $line = <$inst_fh>;
$preamble .= $line;
}
diff --git a/lib/runtime.c b/lib/runtime.c
@@ -15,7 +15,7 @@
#include "runtime.h"
/* Entry point into instrumented application */
-extern struct _scv_node _scv_node0;
+extern struct _citrun_node _citrun_tu_head;
void send_metadata(int);
void send_execution_data(int);
@@ -78,14 +78,17 @@ control_thread(void *arg)
void
send_metadata(int fd)
{
- struct _scv_node walk = _scv_node0;
+ struct _citrun_node walk = _citrun_tu_head;
pid_t process_id, parent_process_id, process_group;
uint64_t num_tus = 0;
size_t file_name_sz;
/* Send the total number of translation unit records we'll send later */
- while (walk.size != 0) {
+ while (1) {
++num_tus;
+
+ if (walk.next == NULL)
+ break;
walk = *walk.next;
}
xwrite(fd, &num_tus, sizeof(num_tus));
@@ -100,9 +103,9 @@ send_metadata(int fd)
xwrite(fd, &parent_process_id, sizeof(pid_t));
xwrite(fd, &process_group, sizeof(pid_t));
- walk = _scv_node0;
+ walk = _citrun_tu_head;
/* Send translation unit records */
- while (walk.size != 0) {
+ while (1) {
/* Send file name size and then the file name itself. */
file_name_sz = strnlen(walk.file_name, PATH_MAX);
xwrite(fd, &file_name_sz, sizeof(file_name_sz));
@@ -114,6 +117,8 @@ send_metadata(int fd)
/* Send the total number of instrumentation sites */
xwrite(fd, &walk.inst_sites, sizeof(walk.size));
+ if (walk.next == NULL)
+ break;
walk = *walk.next;
}
}
@@ -125,11 +130,14 @@ send_metadata(int fd)
void
send_execution_data(int fd)
{
- struct _scv_node walk = _scv_node0;
+ struct _citrun_node walk = _citrun_tu_head;
- while (walk.size != 0) {
+ while (1) {
/* Write execution buffer, one 8 byte counter per source line */
xwrite(fd, walk.lines_ptr, walk.size * sizeof(uint64_t));
+
+ if (walk.next == NULL)
+ break;
walk = *walk.next;
}
}
diff --git a/lib/runtime.h b/lib/runtime.h
@@ -1,9 +1,9 @@
#include <stdint.h>
-struct _scv_node {
+struct _citrun_node {
uint64_t *lines_ptr;
uint32_t size;
uint32_t inst_sites;
const char *file_name;
- struct _scv_node *next;
+ struct _citrun_node *next;
};
void libscv_init();
diff --git a/src/instrument_action.cc b/src/instrument_action.cc
@@ -35,46 +35,55 @@ InstrumentAction::CreateASTConsumer(clang::CompilerInstance &CI, clang::StringRe
#endif
}
-unsigned int
-read_src_number()
+std::string
+get_current_node(std::string file_path)
+{
+ size_t last_slash = file_path.find_last_of('/');
+ std::string fn(file_path.substr(last_slash + 1));
+
+ std::replace(fn.begin(), fn.end(), '.', '_');
+
+ return fn;
+}
+
+std::string
+get_last_node()
{
char *cwd = getcwd(NULL, PATH_MAX);
if (cwd == NULL)
errx(1, "getcwd");
std::string src_number_filename(cwd);
- src_number_filename.append("/SRC_NUMBER");
+ src_number_filename.append("/LAST_NODE");
- if (access(src_number_filename.c_str(), F_OK) == -1) {
- // SRC_NUMBER does not exist, source number is 0
- return 0;
- }
+ if (access(src_number_filename.c_str(), F_OK) == -1)
+ // No LAST_NODE, the .next pointer will be NULL
+ return std::string("NULL");
- // SRC_NUMBER exists, read its content
+ // LAST_NODE exists, read its content
std::ifstream src_number_file;
- unsigned int src_num = 0;
+ std::string last_node;
src_number_file.open(src_number_filename, std::fstream::in);
- src_number_file >> src_num;
+ src_number_file >> last_node;
src_number_file.close();
- // Pre-increment. The current source number is the last one plus one
- return ++src_num;
+ return last_node;
}
void
-write_src_number(int src_num)
+set_last_node(std::string curr_node)
{
char *cwd = getcwd(NULL, PATH_MAX);
if (cwd == NULL)
errx(1, "getcwd");
std::string src_number_filename(cwd);
- src_number_filename.append("/SRC_NUMBER");
+ src_number_filename.append("/LAST_NODE");
std::ofstream src_number_file;
src_number_file.open(src_number_filename, std::fstream::out);
- src_number_file << src_num;
+ src_number_file << curr_node;
src_number_file.close();
}
@@ -92,7 +101,10 @@ InstrumentAction::EndSourceFileAction()
unsigned int num_lines = sm.getPresumedLineNumber(end);
std::string file_name = getCurrentFile();
- unsigned int tu_number = read_src_number();
+ std::string last_node = get_last_node();
+ std::string curr_node = get_current_node(file_name);
+
+ //std::cerr << "LAST NODE = " << last_node << std::endl;
std::stringstream ss;
// Add preprocessor stuff so that the C runtime library links against
@@ -105,23 +117,25 @@ InstrumentAction::EndSourceFileAction()
ss << runtime_h << std::endl;
// Define storage for coverage data
- ss << "static uint64_t _scv_lines[" << num_lines << "];" << std::endl;
-
- // Always declare this. The next TU will overwrite this or there won't
- // be a next TU.
- ss << "struct _scv_node _scv_node" << tu_number + 1 << ";" << std::endl;
+ ss << "static uint64_t _citrun_lines[" << num_lines << "];" << std::endl;
// Get visitor instance to check how many times it rewrote something
RewriteASTVisitor visitor = InstrumentASTConsumer->get_visitor();
+ // Let the struct know this definition will be elsewhere
+ ss << "extern struct _citrun_node _citrun_node_" << last_node << ";" << std::endl;
+
// Define this translation units main book keeping data structure
- ss << "struct _scv_node _scv_node" << tu_number << " = {" << std::endl
- << " .lines_ptr = _scv_lines," << std::endl
+ ss << "struct _citrun_node _citrun_node_" << curr_node << " = {" << std::endl
+ << " .lines_ptr = _citrun_lines," << std::endl
<< " .size = " << num_lines << "," << std::endl
<< " .inst_sites = " << visitor.GetRewriteCount() << "," << std::endl
- << " .file_name = \"" << file_name << "\"," << std::endl
- << " .next = &_scv_node" << tu_number + 1 << "," << std::endl
- << "};" << std::endl;
+ << " .file_name = \"" << file_name << "\"," << std::endl;
+ if (last_node.compare("NULL") == 0)
+ ss << " .next = NULL," << std::endl;
+ else
+ ss << " .next = &_citrun_node_" << last_node << "," << std::endl;
+ ss << "};" << std::endl;
// Close extern "C" {
ss << "#ifdef __cplusplus" << std::endl;
@@ -152,5 +166,5 @@ InstrumentAction::EndSourceFileAction()
// Write the instrumented source file
TheRewriter.getEditBuffer(main_fid).write(output);
- write_src_number(tu_number);
+ set_last_node(curr_node);
}
diff --git a/src/instrument_ast_visitor.cc b/src/instrument_ast_visitor.cc
@@ -48,7 +48,7 @@ RewriteASTVisitor::VisitStmt(clang::Stmt *s)
if (stmt_to_inst == NULL)
return true;
- ss << "(++_scv_lines[" << line << "], ";
+ ss << "(++_citrun_lines[" << line << "], ";
if (TheRewriter.InsertTextBefore(stmt_to_inst->getLocStart(), ss.str()))
// writing failed, don't attempt to add ")"
return true;
diff --git a/src/instrument_main.cc b/src/instrument_main.cc
@@ -167,7 +167,7 @@ main(int argc, char *argv[])
// Instrument source files found on the command line
if (instrument(argc, argv, source_files)) {
- // Instrumentation failed, exec native command
+ warnx("instrumentation failed, running unmodified command");
if (execvp(argv[0], argv))
err(1, "execvp");
}
@@ -185,36 +185,30 @@ main(int argc, char *argv[])
linking = true;
if (linking) {
- char *cwd = getcwd(NULL, PATH_MAX);
- if (cwd == NULL)
- errx(1, "getcwd");
-
- std::string src_number_filename(cwd);
- src_number_filename.append("/SRC_NUMBER");
-
- if (access(src_number_filename.c_str(), F_OK)) {
- // Couldn't access the SRC_NUMBER file, we cannot link
+ std::string last_node_path("LAST_NODE");
+ if (access(last_node_path.c_str(), F_OK)) {
+ // Couldn't access the LAST_NODE file, we cannot link
// to the runtime library without it.
- warnx("SRC_NUMBER file not found.");
+ warnx("LAST_NODE file not found.");
if (execvp(argv[0], argv))
err(1, "execvp");
}
- std::ifstream src_number_file;
- std::string src_number_buffer;
- src_number_file.open(src_number_filename, std::fstream::in);
- src_number_file >> src_number_buffer;
- src_number_file.close();
+ std::ifstream last_node_ifstream;
+ std::string last_node;
+
+ last_node_ifstream.open(last_node_path, std::fstream::in);
+ last_node_ifstream >> last_node;
+ last_node_ifstream.close();
- std::stringstream src_number;
- src_number << "-Wl,--defsym=\"_scv_node0=";
- src_number << src_number_buffer;
- src_number << "\"";
+ std::stringstream defsym_arg;
+ defsym_arg << "-Wl,--defsym=_citrun_tu_head=_citrun_node_";
+ defsym_arg << last_node;
// Add the runtime library and the symbol define hack
// automatically to the command line
- modified_args.push_back("/home/kyle/citrun/lib/libcitrun.so.0.0");
- //modified_args.push_back(const_cast<char *>(src_number.str().c_str()));
+ modified_args.push_back(strdup(defsym_arg.str().c_str()));
+ modified_args.push_back(const_cast<char *>("/home/kyle/citrun/lib/libcitrun.so.0.0"));
}
// Instrumentation succeeded. Run the native compiler with a modified
diff --git a/src/runtime_h.h b/src/runtime_h.h
@@ -1,11 +1,12 @@
static const char runtime_h[] =
"#include <stdint.h>\n"
-"struct _scv_node {\n"
+"#include <stddef.h>\n"
+"struct _citrun_node {\n"
" uint64_t *lines_ptr;\n"
" uint32_t size;\n"
" uint32_t inst_sites;\n"
" const char *file_name;\n"
-" struct _scv_node *next;\n"
+" struct _citrun_node *next;\n"
"};\n"
"void libscv_init();\n"
;
diff --git a/t/fibonacci.t b/t/fibonacci.t
@@ -50,12 +50,12 @@ my $inst_src_good = <<EOF;
long long
fibonacci(long long n)
{
- if ((++_scv_lines[7], n == 0))
- return (++_scv_lines[8], 0);
- else if ((++_scv_lines[9], n == 1))
- return (++_scv_lines[10], 1);
+ if ((++_citrun_lines[7], n == 0))
+ return (++_citrun_lines[8], 0);
+ else if ((++_citrun_lines[9], n == 1))
+ return (++_citrun_lines[10], 1);
- return (++_scv_lines[12], (++_scv_lines[12], fibonacci(n - 1)) + (++_scv_lines[12], fibonacci(n - 2)));
+ return (++_citrun_lines[12], (++_citrun_lines[12], fibonacci(n - 1)) + (++_citrun_lines[12], fibonacci(n - 2)));
}
int
@@ -63,16 +63,16 @@ main(int argc, char *argv[])
{libscv_init();
long long n;
- if ((++_scv_lines[20], argc != 2)) {
- (++_scv_lines[21], printf("usage: %s <N>", argv[0]));
- return (++_scv_lines[22], 1);
+ if ((++_citrun_lines[20], argc != 2)) {
+ (++_citrun_lines[21], printf("usage: %s <N>", argv[0]));
+ return (++_citrun_lines[22], 1);
}
- n = (++_scv_lines[25], atoi(argv[1]));
+ n = (++_citrun_lines[25], atoi(argv[1]));
- (++_scv_lines[27], printf("result: %lli", (++_scv_lines[27], fibonacci(n))));
+ (++_citrun_lines[27], printf("result: %lli", (++_citrun_lines[27], fibonacci(n))));
- return (++_scv_lines[29], 0);
+ return (++_citrun_lines[29], 0);
}
EOF
diff --git a/t/for.t b/t/for.t
@@ -30,11 +30,11 @@ main(void)
{libscv_init();
int i;
- for (i = 0; (++_scv_lines[6], i < 19); i++) {
+ for (i = 0; (++_citrun_lines[6], i < 19); i++) {
i++;
}
- return (++_scv_lines[10], i);
+ return (++_citrun_lines[10], i);
}
EOF
diff --git a/t/hello_world.t b/t/hello_world.t
@@ -27,8 +27,8 @@ my $inst_src_good = <<EOF;
int
main(void)
{libscv_init();
- (++_scv_lines[6], printf("hello, world!"));
- return (++_scv_lines[7], 0);
+ (++_citrun_lines[6], printf("hello, world!"));
+ return (++_citrun_lines[7], 0);
}
EOF
diff --git a/t/if.t b/t/if.t
@@ -37,19 +37,19 @@ my $inst_src_good = <<EOF;
int
main(int argc, char *argv[])
{libscv_init();
- if ((++_scv_lines[6], argc == 1))
- return (++_scv_lines[7], 1);
+ if ((++_citrun_lines[6], argc == 1))
+ return (++_citrun_lines[7], 1);
else
- (++_scv_lines[9], exit(14));
+ (++_citrun_lines[9], exit(14));
- if ((++_scv_lines[11], argc == 2)) {
- return (++_scv_lines[12], 5);
+ if ((++_citrun_lines[11], argc == 2)) {
+ return (++_citrun_lines[12], 5);
}
- else if ((++_scv_lines[14], argc == 3)) {
- return (++_scv_lines[15], 0);
+ else if ((++_citrun_lines[14], argc == 3)) {
+ return (++_citrun_lines[15], 0);
}
else {
- (++_scv_lines[18], exit(0));
+ (++_citrun_lines[18], exit(0));
}
}
EOF
diff --git a/t/inst_preamble.t b/t/inst_preamble.t
@@ -26,23 +26,24 @@ my $preamble_good = <<EOF;
extern "C" {
#endif
#include <stdint.h>
-struct _scv_node {
+#include <stddef.h>
+struct _citrun_node {
uint64_t *lines_ptr;
uint32_t size;
uint32_t inst_sites;
const char *file_name;
- struct _scv_node *next;
+ struct _citrun_node *next;
};
void libscv_init();
-static uint64_t _scv_lines[6];
-struct _scv_node _scv_node1;
-struct _scv_node _scv_node0 = {
- .lines_ptr = _scv_lines,
+static uint64_t _citrun_lines[6];
+extern struct _citrun_node _citrun_node_NULL;
+struct _citrun_node _citrun_node_source_0_c = {
+ .lines_ptr = _citrun_lines,
.size = 6,
.inst_sites = 1,
.file_name = "$tmp_dir/source_0.c",
- .next = &_scv_node1,
+ .next = NULL,
};
#ifdef __cplusplus
}
diff --git a/t/return.t b/t/return.t
@@ -26,15 +26,15 @@ $project->compile();
my $inst_src_good = <<EOF;
int foo() {
- return (++_scv_lines[2], 0);
+ return (++_citrun_lines[2], 0);
}
int main(void) {libscv_init();
- return (++_scv_lines[6], 10);
+ return (++_citrun_lines[6], 10);
- return (++_scv_lines[8], 10 + 10);
+ return (++_citrun_lines[8], 10 + 10);
- return (++_scv_lines[10], (++_scv_lines[10], foo()));
+ return (++_citrun_lines[10], (++_citrun_lines[10], foo()));
}
EOF
diff --git a/t/runtime_sanity.t b/t/runtime_sanity.t
@@ -65,22 +65,22 @@ my $runtime_metadata = $viewer->get_metadata();
my $tus = $runtime_metadata->{tus};
my ($source_0, $source_1, $source_2) = @$tus;
-like( $source_0->{filename}, qr/.*source_0.c/, "runtime filename check 0" );
-is( $source_0->{lines}, 20, "runtime line count check 0" );
+like( $source_0->{filename}, qr/.*source_2.c/, "runtime filename check 0" );
+is( $source_0->{lines}, 9, "runtime line count check 0" );
#is( $source_0->{inst_sites}, 7, "instrumented site count 0" );
like( $source_1->{filename}, qr/.*source_1.c/, "runtime filename check 1" );
is( $source_1->{lines}, 11, "runtime line count check 1" );
#is( $source_1->{inst_sites}, 7, "instrumented site count 1" );
-like( $source_2->{filename}, qr/.*source_2.c/, "runtime filename check 2" );
-is( $source_2->{lines}, 9, "runtime line count check 2" );
+like( $source_2->{filename}, qr/.*source_0.c/, "runtime filename check 2" );
+is( $source_2->{lines}, 20, "runtime line count check 2" );
#is( $source_2->{inst_sites}, 6, "instrumented site count 2" );
# Request and check execution data
my $data = $viewer->get_execution_data($tus);
-my @lines = @{ $data->[0] };
+my @lines = @{ $data->[2] };
is ( $lines[$_], 0, "src 0 line $_ check" ) for (1..11);
is ( $lines[12], 1, "src 0 line 14 check" );
is ( $lines[$_], 0, "src 0 line $_ check" ) for (13..14);
@@ -94,7 +94,7 @@ is ( $lines[$_], 0, "src 1 line $_ check" ) for (0..3);
cmp_ok ( $lines[$_], ">", 10, "src 1 line $_ check" ) for (4..7);
is ( $lines[8], 0, "src 1 line 8 check" );
-my @lines = @{ $data->[2] };
+my @lines = @{ $data->[0] };
is ( $lines[$_], 0, "src 2 line $_ check" ) for (0..8);
$project->kill();
diff --git a/t/switch.t b/t/switch.t
@@ -33,14 +33,14 @@ main(void)
{libscv_init();
int i;
- switch ((++_scv_lines[6], i)) {
+ switch ((++_citrun_lines[6], i)) {
case 0:
break;
case 1:
break;
}
- return (++_scv_lines[13], 0);
+ return (++_citrun_lines[13], 0);
}
EOF
diff --git a/t/while.t b/t/while.t
@@ -32,11 +32,11 @@ main(void)
int i;
i = 0;
- while ((++_scv_lines[7], i < 17)) {
+ while ((++_citrun_lines[7], i < 17)) {
i++;
}
- return (++_scv_lines[11], i);
+ return (++_citrun_lines[11], i);
}
EOF