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

fix #42659, move jl_coverage_visit_line to runtime library #42810

Merged
merged 1 commit into from
Oct 28, 2021
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
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