Skip to content

Commit

Permalink
fix JuliaLang#42659, move jl_coverage_visit_line to runtime library (
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson authored Oct 28, 2021
1 parent c762f10 commit 6a9737d
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 188 deletions.
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ RUNTIME_SRCS := \
simplevector runtime_intrinsics precompile \
threading partr stackwalk gc gc-debug gc-pages gc-stacks method \
jlapi signal-handling safepoint timing subtype \
crc32c APInt-C processor ircode opaque_closure codegen-stubs
crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage
SRCS := jloptions runtime_ccall rtutils
ifeq ($(OS),WINNT)
SRCS += win32_ucontext
Expand Down
3 changes: 0 additions & 3 deletions src/codegen-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ JL_DLLEXPORT void jl_dump_native_fallback(void *native_code,
const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname,
const char *sysimg_data, size_t sysimg_len) UNAVAILABLE
JL_DLLEXPORT int32_t jl_get_llvm_gv_fallback(void *native_code, jl_value_t *p) UNAVAILABLE
JL_DLLEXPORT void jl_write_malloc_log_fallback(void) UNAVAILABLE
JL_DLLEXPORT void jl_write_coverage_data_fallback(const char *output) UNAVAILABLE

JL_DLLEXPORT void jl_clear_malloc_data_fallback(void) UNAVAILABLE
JL_DLLEXPORT int jl_extern_c_fallback(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) UNAVAILABLE
JL_DLLEXPORT jl_value_t *jl_dump_method_asm_fallback(jl_method_instance_t *linfo, size_t world,
char raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) UNAVAILABLE
Expand Down
188 changes: 7 additions & 181 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1803,28 +1803,12 @@ static std::pair<bool, bool> uses_specsig(jl_method_instance_t *lam, jl_value_t

// Logging for code coverage and memory allocation

const int logdata_blocksize = 32; // target getting nearby lines in the same general cache area and reducing calls to malloc by chunking
typedef uint64_t logdata_block[logdata_blocksize];
typedef StringMap< std::vector<logdata_block*> > logdata_t;
JL_DLLEXPORT void jl_coverage_alloc_line(StringRef filename, int line);
JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(StringRef filename, int line);
JL_DLLEXPORT uint64_t *jl_malloc_data_pointer(StringRef filename, int line);

static uint64_t *allocLine(std::vector<logdata_block*> &vec, int line)
static void visitLine(jl_codectx_t &ctx, uint64_t *ptr, Value *addend, const char *name)
{
unsigned block = line / logdata_blocksize;
line = line % logdata_blocksize;
if (vec.size() <= block)
vec.resize(block + 1);
if (vec[block] == NULL) {
vec[block] = (logdata_block*)calloc(1, sizeof(logdata_block));
}
logdata_block &data = *vec[block];
if (data[line] == 0)
data[line] = 1;
return &data[line];
}

static void visitLine(jl_codectx_t &ctx, std::vector<logdata_block*> &vec, int line, Value *addend, const char* name)
{
uint64_t *ptr = allocLine(vec, line);
Value *pv = ConstantExpr::getIntToPtr(
ConstantInt::get(T_size, (uintptr_t)ptr),
T_pint64);
Expand All @@ -1836,38 +1820,16 @@ static void visitLine(jl_codectx_t &ctx, std::vector<logdata_block*> &vec, int l

// Code coverage

static logdata_t coverageData;

static void coverageVisitLine(jl_codectx_t &ctx, StringRef filename, int line)
{
assert(!imaging_mode);
if (filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0)
return;
visitLine(ctx, coverageData[filename], line, ConstantInt::get(T_int64, 1), "lcnt");
}

static void coverageAllocLine(StringRef filename, int line)
{
assert(!imaging_mode);
if (filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0)
return;
allocLine(coverageData[filename], line);
}

extern "C" JL_DLLEXPORT void jl_coverage_visit_line(const char* filename_, size_t len_filename, int line)
{
StringRef filename = StringRef(filename_, len_filename);
if (imaging_mode || filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0)
return;
std::vector<logdata_block*> &vec = coverageData[filename];
uint64_t *ptr = allocLine(vec, line);
(*ptr)++;
visitLine(ctx, jl_coverage_data_pointer(filename, line), ConstantInt::get(T_int64, 1), "lcnt");
}

// Memory allocation log (malloc_log)

static logdata_t mallocData;

static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line, Value *sync)
{
assert(!imaging_mode);
Expand All @@ -1876,143 +1838,7 @@ static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line, Val
Value *addend = sync
? ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync})
: ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
visitLine(ctx, mallocData[filename], line, addend, "bytecnt");
}

// Resets the malloc counts.
extern "C" JL_DLLEXPORT void jl_clear_malloc_data_impl(void)
{
logdata_t::iterator it = mallocData.begin();
for (; it != mallocData.end(); it++) {
std::vector<logdata_block*> &bytes = (*it).second;
std::vector<logdata_block*>::iterator itb;
for (itb = bytes.begin(); itb != bytes.end(); itb++) {
if (*itb) {
logdata_block &data = **itb;
for (int i = 0; i < logdata_blocksize; i++) {
if (data[i] > 0)
data[i] = 1;
}
}
}
}
jl_gc_sync_total_bytes(0);
}

static void write_log_data(logdata_t &logData, const char *extension)
{
std::string base = std::string(jl_options.julia_bindir);
base = base + "/../share/julia/base/";
logdata_t::iterator it = logData.begin();
for (; it != logData.end(); it++) {
std::string filename(it->first());
std::vector<logdata_block*> &values = it->second;
if (!values.empty()) {
if (!jl_isabspath(filename.c_str()))
filename = base + filename;
std::ifstream inf(filename.c_str());
if (!inf.is_open())
continue;
std::string outfile = filename + extension;
std::ofstream outf(outfile.c_str(), std::ofstream::trunc | std::ofstream::out | std::ofstream::binary);
if (outf.is_open()) {
inf.exceptions(std::ifstream::badbit);
outf.exceptions(std::ifstream::failbit | std::ifstream::badbit);
char line[1024];
int l = 1;
unsigned block = 0;
while (!inf.eof()) {
inf.getline(line, sizeof(line));
if (inf.fail()) {
if (inf.eof())
break; // no content on trailing line
// Read through lines longer than sizeof(line)
inf.clear();
inf.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
logdata_block *data = NULL;
if (block < values.size()) {
data = values[block];
}
uint64_t value = data ? (*data)[l] : 0;
if (++l >= logdata_blocksize) {
l = 0;
block++;
}
outf.width(9);
if (value == 0)
outf << '-';
else
outf << (value - 1);
outf.width(0);
outf << " " << line << '\n';
}
outf.close();
}
inf.close();
}
}
}

static void write_lcov_data(logdata_t &logData, const std::string &outfile)
{
std::ofstream outf(outfile.c_str(), std::ofstream::ate | std::ofstream::out | std::ofstream::binary);
//std::string base = std::string(jl_options.julia_bindir);
//base = base + "/../share/julia/base/";
logdata_t::iterator it = logData.begin();
for (; it != logData.end(); it++) {
StringRef filename = it->first();
const std::vector<logdata_block*> &values = it->second;
if (!values.empty()) {
outf << "SF:" << filename.str() << '\n';
size_t n_covered = 0;
size_t n_instrumented = 0;
size_t lno = 0;
for (auto &itv : values) {
if (itv) {
logdata_block &data = *itv;
for (int i = 0; i < logdata_blocksize; i++) {
auto cov = data[i];
if (cov > 0) {
n_instrumented++;
if (cov > 1)
n_covered++;
outf << "DA:" << lno << ',' << (cov - 1) << '\n';
}
lno++;
}
}
else {
lno += logdata_blocksize;
}
}
outf << "LH:" << n_covered << '\n';
outf << "LF:" << n_instrumented << '\n';
outf << "end_of_record\n";
}
}
outf.close();
}

extern "C" JL_DLLEXPORT void jl_write_coverage_data_impl(const char *output)
{
if (output) {
StringRef output_pattern(output);
if (output_pattern.endswith(".info"))
write_lcov_data(coverageData, jl_format_filename(output_pattern.str().c_str()));
}
else {
std::string stm;
raw_string_ostream(stm) << "." << jl_getpid() << ".cov";
write_log_data(coverageData, stm.c_str());
}
}

extern "C" JL_DLLEXPORT void jl_write_malloc_log_impl(void)
{
std::string stm;
raw_string_ostream(stm) << "." << jl_getpid() << ".mem";
write_log_data(mallocData, stm.c_str());
visitLine(ctx, jl_malloc_data_pointer(filename, line), addend, "bytecnt");
}

// --- constant determination ---
Expand Down Expand Up @@ -7073,7 +6899,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
// record all lines that could be covered
for (const auto &info : linetable)
if (do_coverage(info.is_user_code))
coverageAllocLine(info.file, info.line);
jl_coverage_alloc_line(info.file, info.line);
}

come_from_bb[0] = ctx.builder.GetInsertBlock();
Expand Down
Loading

0 comments on commit 6a9737d

Please sign in to comment.