Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license 2 : : 3 : : #include <string> 4 : : #include <fstream> 5 : : #include <map> 6 : : #include <vector> 7 : : 8 : : #include "llvm-version.h" 9 : : #include <llvm/ADT/StringRef.h> 10 : : #include <llvm/ADT/StringMap.h> 11 : : #include <llvm/Support/raw_ostream.h> 12 : : 13 : : #include "julia.h" 14 : : #include "julia_internal.h" 15 : : 16 : : using namespace llvm; 17 : : 18 : 0 : static int codegen_imaging_mode(void) 19 : : { 20 [ # # # # : 0 : return jl_options.image_codegen || (jl_generating_output() && !jl_options.incremental); # # ] 21 : : } 22 : : 23 : : // Logging for code coverage and memory allocation 24 : : 25 : : const int logdata_blocksize = 32; // target getting nearby lines in the same general cache area and reducing calls to malloc by chunking 26 : : typedef uint64_t logdata_block[logdata_blocksize]; 27 : : typedef StringMap< std::vector<logdata_block*> > logdata_t; 28 : : 29 : 0 : static uint64_t *allocLine(std::vector<logdata_block*> &vec, int line) 30 : : { 31 : 0 : unsigned block = line / logdata_blocksize; 32 : 0 : line = line % logdata_blocksize; 33 [ # # ]: 0 : if (vec.size() <= block) 34 : 0 : vec.resize(block + 1); 35 [ # # ]: 0 : if (vec[block] == NULL) { 36 : 0 : vec[block] = (logdata_block*)calloc(1, sizeof(logdata_block)); 37 : : } 38 : 0 : logdata_block &data = *vec[block]; 39 [ # # ]: 0 : if (data[line] == 0) 40 : 0 : data[line] = 1; 41 : 0 : return &data[line]; 42 : : } 43 : : 44 : : // Code coverage 45 : : 46 : : static logdata_t coverageData; 47 : : 48 : 0 : JL_DLLEXPORT void jl_coverage_alloc_line(StringRef filename, int line) 49 : : { 50 : : assert(!codegen_imaging_mode()); 51 [ # # # # : 0 : if (filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0) # # # # # # # # ] 52 : 0 : return; 53 : 0 : allocLine(coverageData[filename], line); 54 : : } 55 : : 56 : 0 : JL_DLLEXPORT uint64_t *jl_coverage_data_pointer(StringRef filename, int line) 57 : : { 58 : 0 : return allocLine(coverageData[filename], line); 59 : : } 60 : : 61 : 0 : extern "C" JL_DLLEXPORT void jl_coverage_visit_line(const char *filename_, size_t len_filename, int line) 62 : : { 63 : 0 : StringRef filename = StringRef(filename_, len_filename); 64 [ # # # # : 0 : if (codegen_imaging_mode() || filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0) # # # # # # # # # # ] 65 : 0 : return; 66 : 0 : std::vector<logdata_block*> &vec = coverageData[filename]; 67 : 0 : uint64_t *ptr = allocLine(vec, line); 68 : 0 : (*ptr)++; 69 : : } 70 : : 71 : : // Memory allocation log (malloc_log) 72 : : 73 : : static logdata_t mallocData; 74 : : 75 : 0 : JL_DLLEXPORT uint64_t *jl_malloc_data_pointer(StringRef filename, int line) 76 : : { 77 : 0 : return allocLine(mallocData[filename], line); 78 : : } 79 : : 80 : : // Resets the malloc counts. 81 : 0 : extern "C" JL_DLLEXPORT void jl_clear_malloc_data(void) 82 : : { 83 : 0 : logdata_t::iterator it = mallocData.begin(); 84 [ # # ]: 0 : for (; it != mallocData.end(); it++) { 85 : 0 : std::vector<logdata_block*> &bytes = (*it).second; 86 : 0 : std::vector<logdata_block*>::iterator itb; 87 [ # # ]: 0 : for (itb = bytes.begin(); itb != bytes.end(); itb++) { 88 [ # # ]: 0 : if (*itb) { 89 : 0 : logdata_block &data = **itb; 90 [ # # ]: 0 : for (int i = 0; i < logdata_blocksize; i++) { 91 [ # # ]: 0 : if (data[i] > 0) 92 : 0 : data[i] = 1; 93 : : } 94 : : } 95 : : } 96 : : } 97 : 0 : jl_gc_sync_total_bytes(0); 98 : 0 : } 99 : : 100 : 0 : static void write_log_data(logdata_t &logData, const char *extension) 101 : : { 102 : 0 : std::string base = std::string(jl_options.julia_bindir); 103 : 0 : base = base + "/../share/julia/base/"; 104 : 0 : logdata_t::iterator it = logData.begin(); 105 [ # # ]: 0 : for (; it != logData.end(); it++) { 106 : 0 : std::string filename(it->first()); 107 : 0 : std::vector<logdata_block*> &values = it->second; 108 [ # # ]: 0 : if (!values.empty()) { 109 [ # # ]: 0 : if (!jl_isabspath(filename.c_str())) 110 : 0 : filename = base + filename; 111 : 0 : std::ifstream inf(filename.c_str()); 112 [ # # ]: 0 : if (!inf.is_open()) 113 : 0 : continue; 114 : 0 : std::string outfile = filename + extension; 115 : 0 : std::ofstream outf(outfile.c_str(), std::ofstream::trunc | std::ofstream::out | std::ofstream::binary); 116 [ # # ]: 0 : if (outf.is_open()) { 117 : 0 : inf.exceptions(std::ifstream::badbit); 118 : 0 : outf.exceptions(std::ifstream::failbit | std::ifstream::badbit); 119 : : char line[1024]; 120 : 0 : int l = 1; 121 : 0 : unsigned block = 0; 122 [ # # ]: 0 : while (!inf.eof()) { 123 : 0 : inf.getline(line, sizeof(line)); 124 [ # # ]: 0 : if (inf.fail()) { 125 [ # # ]: 0 : if (inf.eof()) 126 : 0 : break; // no content on trailing line 127 : : // Read through lines longer than sizeof(line) 128 : 0 : inf.clear(); 129 : 0 : inf.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 130 : : } 131 : 0 : logdata_block *data = NULL; 132 [ # # ]: 0 : if (block < values.size()) { 133 : 0 : data = values[block]; 134 : : } 135 [ # # ]: 0 : uint64_t value = data ? (*data)[l] : 0; 136 [ # # ]: 0 : if (++l >= logdata_blocksize) { 137 : 0 : l = 0; 138 : 0 : block++; 139 : : } 140 : 0 : outf.width(9); 141 [ # # ]: 0 : if (value == 0) 142 : 0 : outf << '-'; 143 : : else 144 : 0 : outf << (value - 1); 145 : 0 : outf.width(0); 146 : 0 : outf << " " << line << '\n'; 147 : : } 148 : 0 : outf.close(); 149 : : } 150 : 0 : inf.close(); 151 : : } 152 : : } 153 : 0 : } 154 : : 155 : 0 : static void write_lcov_data(logdata_t &logData, const std::string &outfile) 156 : : { 157 : 0 : std::ofstream outf(outfile.c_str(), std::ofstream::ate | std::ofstream::out | std::ofstream::binary); 158 : : //std::string base = std::string(jl_options.julia_bindir); 159 : : //base = base + "/../share/julia/base/"; 160 : 0 : logdata_t::iterator it = logData.begin(); 161 [ # # ]: 0 : for (; it != logData.end(); it++) { 162 : 0 : StringRef filename = it->first(); 163 : 0 : const std::vector<logdata_block*> &values = it->second; 164 [ # # ]: 0 : if (!values.empty()) { 165 : 0 : outf << "SF:" << filename.str() << '\n'; 166 : 0 : size_t n_covered = 0; 167 : 0 : size_t n_instrumented = 0; 168 : 0 : size_t lno = 0; 169 [ # # ]: 0 : for (auto &itv : values) { 170 [ # # ]: 0 : if (itv) { 171 : 0 : logdata_block &data = *itv; 172 [ # # ]: 0 : for (int i = 0; i < logdata_blocksize; i++) { 173 : 0 : auto cov = data[i]; 174 [ # # ]: 0 : if (cov > 0) { 175 : 0 : n_instrumented++; 176 [ # # ]: 0 : if (cov > 1) 177 : 0 : n_covered++; 178 : 0 : outf << "DA:" << lno << ',' << (cov - 1) << '\n'; 179 : : } 180 : 0 : lno++; 181 : : } 182 : : } 183 : : else { 184 : 0 : lno += logdata_blocksize; 185 : : } 186 : : } 187 : 0 : outf << "LH:" << n_covered << '\n'; 188 : 0 : outf << "LF:" << n_instrumented << '\n'; 189 : 0 : outf << "end_of_record\n"; 190 : : } 191 : : } 192 : 0 : outf.close(); 193 : 0 : } 194 : : 195 : 0 : extern "C" JL_DLLEXPORT void jl_write_coverage_data(const char *output) 196 : : { 197 [ # # ]: 0 : if (output) { 198 : 0 : StringRef output_pattern(output); 199 [ # # ]: 0 : if (output_pattern.endswith(".info")) 200 : 0 : write_lcov_data(coverageData, jl_format_filename(output_pattern.str().c_str())); 201 : : } 202 : : else { 203 : 0 : std::string stm; 204 : 0 : raw_string_ostream(stm) << "." << uv_os_getpid() << ".cov"; 205 : 0 : write_log_data(coverageData, stm.c_str()); 206 : : } 207 : 0 : } 208 : : 209 : 0 : extern "C" JL_DLLEXPORT void jl_write_malloc_log(void) 210 : : { 211 : 0 : std::string stm; 212 : 0 : raw_string_ostream(stm) << "." << uv_os_getpid() << ".mem"; 213 : 0 : write_log_data(mallocData, stm.c_str()); 214 : 0 : }