Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simple code coverage tool #5423

Merged
merged 2 commits into from
Jan 21, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@

#include <string>
#include <sstream>
#include <fstream>
#include <map>
#include <vector>
#include <set>
Expand Down Expand Up @@ -273,12 +274,6 @@ struct jl_varinfo_t {
};

// --- helpers for reloading IR image
extern "C"
void jl_set_imaging_mode(int stat)
{
imaging_mode = !!stat;
}

static void jl_gen_llvm_gv_array();

extern "C"
Expand Down Expand Up @@ -3080,6 +3075,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
ctx.f = f;

// step 5. set up debug info context and create first basic block
bool do_coverage =
jl_compileropts.code_coverage && lam->module != jl_base_module && lam->module != jl_core_module;
jl_value_t *stmt = jl_cellref(stmts,0);
std::string filename = "no file";
char *dbgFuncName = lam->name->name;
Expand Down Expand Up @@ -3124,6 +3121,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
// special value: if function name is empty, disable debug info
builder.SetCurrentDebugLocation(noDbg);
debug_enabled = false;
do_coverage = false;
}
else {
// TODO: Fix when moving to new LLVM version
Expand Down Expand Up @@ -3430,12 +3428,16 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
int lno = jl_linenode_line(stmt);
if (debug_enabled)
builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, (MDNode*)SP, NULL));
if (do_coverage)
coverageVisitLine(filename, lno);
ctx.lineno = lno;
}
else if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == line_sym) {
int lno = jl_unbox_long(jl_exprarg(stmt, 0));
if (debug_enabled)
builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, (MDNode*)SP, NULL));
if (do_coverage)
coverageVisitLine(filename, lno);
ctx.lineno = lno;
}
if (jl_is_labelnode(stmt)) {
Expand Down Expand Up @@ -3985,6 +3987,8 @@ static void init_julia_llvm_env(Module *m)

extern "C" void jl_init_codegen(void)
{
imaging_mode = jl_compileropts.build_path != NULL;

InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
Expand Down
64 changes: 64 additions & 0 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,67 @@ class JITMemoryManagerWin : public JITMemoryManager {
virtual void registerEHFrames(StringRef SectionData) { return JMM->registerEHFrames(SectionData); }
};
#endif

// Code coverage

typedef std::map<std::string,std::vector<GlobalVariable*> > coveragedata_t;
static coveragedata_t coverageData;

static void coverageVisitLine(std::string filename, int line)
{
if (filename == "" || filename == "none" || filename == "no file")
return;
coveragedata_t::iterator it = coverageData.find(filename);
if (it == coverageData.end()) {
coverageData[filename] = std::vector<GlobalVariable*>(0);
}
std::vector<GlobalVariable*> &vec = coverageData[filename];
if (vec.size() <= (size_t)line)
vec.resize(line+1, NULL);
if (vec[line] == NULL)
vec[line] = new GlobalVariable(*jl_Module, T_int64, false, GlobalVariable::InternalLinkage,
ConstantInt::get(T_int64,0), "lcnt");
GlobalVariable *v = vec[line];
builder.CreateStore(builder.CreateAdd(builder.CreateLoad(v),
ConstantInt::get(T_int64,1)),
v);
}

extern "C" void jl_write_coverage_data(void)
{
coveragedata_t::iterator it = coverageData.begin();
for (; it != coverageData.end(); it++) {
std::string filename = (*it).first;
std::string outfile = filename + ".cov";
std::vector<GlobalVariable*> &counts = (*it).second;
if (counts.size() > 1) {
std::ifstream inf(filename.c_str());
if (inf.is_open()) {
std::ofstream outf(outfile.c_str(), std::ofstream::trunc | std::ofstream::out);
char line[1024];
int l = 1;
while (!inf.eof()) {
inf.getline(line, sizeof(line));
int count = -1;
if ((size_t)l < counts.size()) {
GlobalVariable *gv = counts[l];
if (gv) {
int *p = (int*)jl_ExecutionEngine->getPointerToGlobal(gv);
count = *p;
}
}
outf.width(9);
if (count == -1)
outf<<'-';
else
outf<<count;
outf.width(0);
outf<<" "<<line<<std::endl;
l++;
}
outf.close();
inf.close();
}
}
}
}
3 changes: 2 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,14 +989,15 @@ extern void jl_get_system_hooks(void);
extern void jl_get_uv_hooks(void);

DLLEXPORT
void jl_restore_system_image(char *fname, int build_mode)
void jl_restore_system_image(char *fname)
{
ios_t f;
char *fpath = fname;
if (ios_file(&f, fpath, 1, 0, 0, 0) == NULL) {
JL_PRINTF(JL_STDERR, "System image file \"%s\" not found\n", fname);
exit(1);
}
int build_mode = (jl_compileropts.build_path != NULL);
#ifdef _OS_WINDOWS_
//XXX: the windows linker forces our system image to be
// linked against only one dll, I picked libjulia-release
Expand Down
18 changes: 13 additions & 5 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ extern BOOL (WINAPI *hSymRefreshModuleList)(HANDLE);
#include <sched.h> // for setting CPU affinity
#endif

char *julia_home = NULL;
jl_compileropts_t jl_compileropts = { NULL, // build_path
0 // code_coverage
};

int jl_boot_file_loaded = 0;

char *jl_stack_lo;
Expand Down Expand Up @@ -350,11 +355,15 @@ static void jl_uv_exitcleanup_walk(uv_handle_t* handle, void *arg)
jl_uv_exitcleanup_add(handle, (struct uv_shutdown_queue*)arg);
}

void jl_write_coverage_data(void);

DLLEXPORT void uv_atexit_hook()
{
#if defined(JL_GC_MARKSWEEP) && defined(GC_FINAL_STATS)
jl_print_gc_stats(JL_STDERR);
#endif
if (jl_compileropts.code_coverage)
jl_write_coverage_data();
if (jl_base_module) {
jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit"));
if (f!=NULL && jl_is_function(f)) {
Expand Down Expand Up @@ -622,10 +631,8 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,

#endif

void julia_init(char *imageFile, int build_mode)
void julia_init(char *imageFile)
{
if (build_mode)
jl_set_imaging_mode(1);
jl_page_size = jl_getpagesize();
jl_find_stack_bottom();
jl_dl_handle = jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT);
Expand Down Expand Up @@ -704,7 +711,7 @@ void julia_init(char *imageFile, int build_mode)

if (imageFile) {
JL_TRY {
jl_restore_system_image(imageFile, build_mode);
jl_restore_system_image(imageFile);
}
JL_CATCH {
JL_PRINTF(JL_STDERR, "error during init:\n");
Expand Down Expand Up @@ -830,7 +837,7 @@ DLLEXPORT void jl_install_sigint_handler()
extern int asprintf(char **str, const char *fmt, ...);
extern void * __stack_chk_guard;

DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *av[]), char *build_path)
DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *av[]))
{
#if defined(_OS_WINDOWS_)
SetUnhandledExceptionFilter(exception_handler);
Expand All @@ -851,6 +858,7 @@ DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *
}
#endif
int ret = pmain(argc, argv);
char *build_path = jl_compileropts.build_path;
if (build_path) {
char *build_ji;
if (asprintf(&build_ji, "%s.ji",build_path) > 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ DLLEXPORT void jl_init(char *julia_home_dir)
{
libsupport_init();
char *image_file = jl_locate_sysimg(julia_home_dir, JL_SYSTEM_IMAGE_PATH);
julia_init(image_file, 0);
julia_init(image_file);
jl_set_const(jl_core_module, jl_symbol("JULIA_HOME"),
jl_cstr_to_string(julia_home));
jl_module_export(jl_core_module, jl_symbol("JULIA_HOME"));
Expand Down
22 changes: 15 additions & 7 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,8 @@ jl_value_t *jl_no_method_error(jl_function_t *f, jl_value_t **args, size_t na);
void jl_check_type_tuple(jl_tuple_t *t, jl_sym_t *name, const char *ctx);

// initialization functions
DLLEXPORT void julia_init(char *imageFile, int build_mode);
DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[]), char* build_mode);
DLLEXPORT void julia_init(char *imageFile);
DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[]));
void jl_init_types(void);
void jl_init_box_caches(void);
DLLEXPORT void jl_init_frontend(void);
Expand All @@ -897,9 +897,8 @@ void jl_init_tasks(void *stack, size_t ssize);
void jl_init_serializer(void);

DLLEXPORT void jl_save_system_image(char *fname);
DLLEXPORT void jl_restore_system_image(char *fname, int build_mode);
DLLEXPORT void jl_restore_system_image(char *fname);
void jl_dump_bitcode(char *fname);
void jl_set_imaging_mode(int stat);
int32_t jl_get_llvm_gv(jl_value_t *p);

// front end interface
Expand Down Expand Up @@ -1267,9 +1266,9 @@ size_t rec_backtrace_ctx_dwarf(ptrint_t *data, size_t maxsize, bt_context_t ctx)


//IO objects
extern DLLEXPORT uv_stream_t *jl_uv_stdin;
extern DLLEXPORT uv_stream_t * jl_uv_stdout;
extern DLLEXPORT uv_stream_t * jl_uv_stderr;
extern DLLEXPORT uv_stream_t *jl_uv_stdin;
extern DLLEXPORT uv_stream_t *jl_uv_stdout;
extern DLLEXPORT uv_stream_t *jl_uv_stderr;

DLLEXPORT JL_STREAM *jl_stdout_stream(void);
DLLEXPORT JL_STREAM *jl_stdin_stream(void);
Expand Down Expand Up @@ -1334,6 +1333,15 @@ void jl_longjmp(jmp_buf _Buf,int _Value);
for (i__ca=1, jl_eh_restore_state(&__eh); i__ca; i__ca=0)
#endif

// Compiler options

typedef struct {
char *build_path;
int code_coverage;
} jl_compileropts_t;

extern DLLEXPORT jl_compileropts_t jl_compileropts;

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 0 additions & 1 deletion src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "julia.h"
#include "builtin_proto.h"

char *julia_home = NULL;
// current line number in a file
int jl_lineno = 0;

Expand Down
28 changes: 15 additions & 13 deletions ui/repl.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ static int lisp_prompt = 0;
static char *program = NULL;
char *image_file = NULL;
int tab_width = 2;
char *build_mode = NULL;

static const char *usage = "julia [options] [program] [args...]\n";
static const char *opts =
" -v --version Display version information\n"
" -h --help Print this message\n"
" -q --quiet Quiet startup without banner\n"
" -H --home <dir> Load files relative to <dir>\n"
" -H --home <dir> Set location of julia executable\n"
" -T --tab <size> Set REPL tab width to <size>\n\n"

" -e --eval <expr> Evaluate <expr>\n"
Expand All @@ -39,17 +39,19 @@ static const char *opts =
" -F Load ~/.juliarc.jl, then handle remaining inputs\n"
" --color=yes|no Enable or disable color text\n\n"

" -h --help Print this message\n";
" --code-coverage Count executions of source lines\n";

void parse_opts(int *argcp, char ***argvp) {
void parse_opts(int *argcp, char ***argvp)
{
static char* shortopts = "+H:T:hJ:";
static struct option longopts[] = {
{ "home", required_argument, 0, 'H' },
{ "tab", required_argument, 0, 'T' },
{ "build", required_argument, 0, 'b' },
{ "lisp", no_argument, &lisp_prompt, 1 },
{ "help", no_argument, 0, 'h' },
{ "sysimage", required_argument, 0, 'J' },
{ "home", required_argument, 0, 'H' },
{ "tab", required_argument, 0, 'T' },
{ "build", required_argument, 0, 'b' },
{ "lisp", no_argument, &lisp_prompt, 1 },
{ "help", no_argument, 0, 'h' },
{ "sysimage", required_argument, 0, 'J' },
{ "code-coverage", no_argument, &jl_compileropts.code_coverage, 1 },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JeffBezanson I think this broke my Windows build;

$ cd ui
$ make VERBOSE=1 DEFAULT_REPL=basic XC_HOST=x86_64-w64-mingw32                         
x86_64-w64-mingw32-gcc -std=gnu99 -pipe -fno-strict-aliasing -D_FILE_OFFSET_BITS=64 -DJL_SYSTEM_IMAGE_PATH="/sys.ji" -D_WIN32_WINNT=0x0600 -O3 -falign-functions -momit-leaf-frame-pointer -Wall -Wno-strict-aliasing -fno-omit-frame-pointer -I/home/sabae/tmp/wintest/julia/src -I/home/sabae/tmp/wintest/julia/src/support -I/home/sabae/tmp/wintest/julia/usr/include -c repl.c -o repl.o
repl.c: In function 'parse_opts':
repl.c:56:9: error: initializer element is not constant
         { "code-coverage", no_argument,       &jl_compileropts.code_coverage, 1 },
         ^
repl.c:56:9: error: (near initialization for 'longopts[6].flag')
make: *** [repl.o] Error 1

I'm guessing this is because the cross-compiler is running in some C mode that "normal" native compiles don't? Is there a simple fix we can take to ensure this doesn't happen even in strict C modes?

{ 0, 0, 0, 0 }
};
int c;
Expand All @@ -74,7 +76,7 @@ void parse_opts(int *argcp, char ***argvp) {
tab_width = atoi(optarg);
break;
case 'b':
build_mode = strdup(optarg);
jl_compileropts.build_path = strdup(optarg);
if (!imagepathspecified)
image_file = NULL;
break;
Expand Down Expand Up @@ -289,6 +291,6 @@ int main(int argc, char *argv[])
jl_lisp_prompt();
return 0;
}
julia_init(lisp_prompt ? NULL : image_file, build_mode!=NULL);
return julia_trampoline(argc, argv, true_main, build_mode);
julia_init(lisp_prompt ? NULL : image_file);
return julia_trampoline(argc, argv, true_main);
}