Remove defunct test coverage
This commit is contained in:
parent
caa08e8d4e
commit
941208c948
9
Makefile
9
Makefile
|
@ -1,7 +1,6 @@
|
|||
CLOSURE_DIR=closure-compiler
|
||||
CLOSURE=$(CLOSURE_DIR)/compiler.jar
|
||||
NASM_TEST_DIR=./tests/nasm
|
||||
COVERAGE_DIR=./tests/coverage
|
||||
|
||||
INSTRUCTION_TABLES=src/rust/gen/jit.rs src/rust/gen/jit0f_16.rs src/rust/gen/jit0f_32.rs \
|
||||
src/rust/gen/interpreter.rs src/rust/gen/interpreter0f_16.rs src/rust/gen/interpreter0f_32.rs \
|
||||
|
@ -85,7 +84,7 @@ CARGO_FLAGS=\
|
|||
-C link-args="--import-table --global-base=8388608 $(STRIP_DEBUG_FLAG)" \
|
||||
--verbose
|
||||
|
||||
CORE_FILES=const.js config.js io.js main.js lib.js coverage.js ide.js pci.js floppy.js \
|
||||
CORE_FILES=const.js config.js io.js main.js lib.js ide.js pci.js floppy.js \
|
||||
memory.js dma.js pit.js vga.js ps2.js pic.js rtc.js uart.js hpet.js acpi.js apic.js ioapic.js \
|
||||
state.js ne2k.js virtio.js bus.js log.js \
|
||||
cpu.js debug.js \
|
||||
|
@ -200,8 +199,6 @@ clean:
|
|||
-rm $(addsuffix .diff,$(INSTRUCTION_TABLES))
|
||||
-rm build/*.map
|
||||
-rm build/*.wast
|
||||
-rm build/coverage/coverage_data*
|
||||
-rm $(COVERAGE_DIR)/build/*
|
||||
$(MAKE) -C $(NASM_TEST_DIR) clean
|
||||
|
||||
run:
|
||||
|
@ -291,10 +288,6 @@ all-tests: jshint kvm-unit-test expect-tests qemutests jitpagingtests api-tests
|
|||
# - debiantests (requires network)
|
||||
# - devices-test (hangs)
|
||||
|
||||
covreport:
|
||||
mkdir -p $(COVERAGE_DIR)/build/
|
||||
$(COVERAGE_DIR)/gen_report.js
|
||||
|
||||
node_modules/.bin/jshint:
|
||||
npm install
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"use strict";
|
||||
|
||||
var CORE_FILES =
|
||||
"const.js config.js log.js lib.js coverage.js cpu.js debug.js " +
|
||||
"const.js config.js log.js lib.js cpu.js debug.js " +
|
||||
"io.js main.js ide.js pci.js floppy.js " +
|
||||
"memory.js dma.js pit.js vga.js ps2.js pic.js rtc.js uart.js acpi.js apic.js ioapic.js hpet.js " +
|
||||
"ne2k.js state.js virtio.js bus.js elf.js kernel.js";
|
||||
|
|
|
@ -71,8 +71,3 @@ var APIC_TIMER_FREQ = TSC_RATE;
|
|||
|
||||
/** @const */
|
||||
var VMWARE_HYPERVISOR_PORT = true;
|
||||
|
||||
/** @const
|
||||
* Whether the coverage logger should be enabled under the appropriate conditions
|
||||
*/
|
||||
const COVERAGE_LOGGER_ALLOW = true;
|
||||
|
|
|
@ -361,8 +361,3 @@ const WASM_EXPORT_TABLE_NAME = "__indirect_function_table";
|
|||
|
||||
/** @const */
|
||||
const WASM_PAGE_SIZE = 64 * 1024;
|
||||
|
||||
/** @const */
|
||||
const COVERAGE_EXPORT_PREFIX = "___profn_";
|
||||
/** @const */
|
||||
const COVERAGE_FILE_PREFIX = "coverage_data";
|
||||
|
|
133
src/coverage.js
133
src/coverage.js
|
@ -1,133 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const is_env_node = v86util.check_env_node();
|
||||
const fs = is_env_node && require("fs");
|
||||
const path = is_env_node && require("path");
|
||||
|
||||
/** @constructor */
|
||||
function CoverageLogger()
|
||||
{
|
||||
this.ENABLED = COVERAGE_LOGGER_ALLOW && DEBUG && is_env_node;
|
||||
if(!this.ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.should_log_coverage = false;
|
||||
this.memory_base = 0;
|
||||
}
|
||||
|
||||
CoverageLogger.prototype.log_start = function()
|
||||
{
|
||||
if(!this.ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.should_log_coverage = true;
|
||||
};
|
||||
|
||||
CoverageLogger.prototype.log_end = function()
|
||||
{
|
||||
if(!this.ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.should_log_coverage = false;
|
||||
};
|
||||
|
||||
CoverageLogger.prototype.init = function(wm)
|
||||
{
|
||||
if(!this.ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.coverage_map = {};
|
||||
this.memory_base = wm.imports.env["memoryBase"];
|
||||
this.COVERAGE_DATA_PATH = path.join(__dirname, "coverage");
|
||||
|
||||
for(let name of Object.keys(wm.exports))
|
||||
{
|
||||
if(name.startsWith(COVERAGE_EXPORT_PREFIX))
|
||||
{
|
||||
const fn_id = wm.exports[name];
|
||||
this.coverage_map[fn_id] = {};
|
||||
|
||||
const coverage_data = this.coverage_map[fn_id];
|
||||
// fn_id -> func_name
|
||||
coverage_data.fn_name = name.slice(COVERAGE_EXPORT_PREFIX.length);
|
||||
// fn_id -> block_covered ([0,2,3])
|
||||
coverage_data.visit_logs = new Uint8Array(8);
|
||||
// Position within visit_logs from where to append data
|
||||
coverage_data.pos = 0;
|
||||
// Total number of conditional blocks in fn_id
|
||||
coverage_data.total_blocks = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CoverageLogger.prototype.log = function(fn_name_offset, num_blocks, visited_block)
|
||||
{
|
||||
if(!this.ENABLED || !this.should_log_coverage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// fn_name_offset is an offset in the data section to where the string of the function
|
||||
// name is stored, so it varies by memoryBase, whereas the __profn exported fn_id doesn't
|
||||
const fn_id = fn_name_offset - this.memory_base;
|
||||
const coverage_data = this.coverage_map[fn_id];
|
||||
if(!coverage_data)
|
||||
{
|
||||
// Static functions may not be "discovered" in coverage_init - we currently simply
|
||||
// skip them
|
||||
return;
|
||||
}
|
||||
|
||||
const log_pos = coverage_data.pos;
|
||||
const existing_entry = coverage_data.visit_logs.indexOf(visited_block);
|
||||
if((existing_entry > -1 && existing_entry < log_pos) || num_blocks > 0xFF)
|
||||
{
|
||||
// If we'd like to profile frequency of code visited, we should be using counters
|
||||
// instead. This approach was simply faster to measure coverage.
|
||||
return;
|
||||
}
|
||||
|
||||
coverage_data.total_blocks = num_blocks;
|
||||
coverage_data.visit_logs[log_pos] = visited_block;
|
||||
coverage_data.pos++;
|
||||
|
||||
if(log_pos >= coverage_data.visit_logs.length - 1)
|
||||
{
|
||||
this.dump_to_files();
|
||||
coverage_data.pos = 0;
|
||||
}
|
||||
};
|
||||
|
||||
CoverageLogger.prototype.dump_to_files = function()
|
||||
{
|
||||
if(!this.ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(let fn_id of Object.keys(this.coverage_map))
|
||||
{
|
||||
const coverage_data = this.coverage_map[fn_id];
|
||||
if(coverage_data.pos)
|
||||
{
|
||||
const fn_name = coverage_data.fn_name;
|
||||
const total_blocks = coverage_data.total_blocks;
|
||||
const filename = path.join(
|
||||
this.COVERAGE_DATA_PATH,
|
||||
`${COVERAGE_FILE_PREFIX}_${fn_name}_${total_blocks}`
|
||||
);
|
||||
// XXX: Experiment more with async I/O - preliminarily it seemed to choke the nasm test
|
||||
// even when limiting max files open simultaneously
|
||||
fs["appendFileSync"](
|
||||
filename,
|
||||
Buffer.from(coverage_data.visit_logs.buffer, 0, coverage_data.pos)
|
||||
);
|
||||
coverage_data.pos = 0;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -11,11 +11,10 @@ var CPU_LOG_VERBOSE = false;
|
|||
|
||||
|
||||
/** @constructor */
|
||||
function CPU(bus, wm, v86oxide, coverage_logger)
|
||||
function CPU(bus, wm, v86oxide)
|
||||
{
|
||||
this.wm = wm;
|
||||
this.v86oxide = v86oxide;
|
||||
this.coverage_logger = coverage_logger;
|
||||
this.wasm_patch(wm);
|
||||
this.create_jit_imports();
|
||||
|
||||
|
@ -1360,9 +1359,6 @@ let do_many_cycles_total = 0;
|
|||
|
||||
CPU.prototype.do_many_cycles = function()
|
||||
{
|
||||
// Capture the total time we were executing instructions
|
||||
//this.coverage_logger.log_start();
|
||||
|
||||
if(ENABLE_PROFILER)
|
||||
{
|
||||
var start_time = v86.microtick();
|
||||
|
@ -1375,8 +1371,6 @@ CPU.prototype.do_many_cycles = function()
|
|||
do_many_cycles_total += v86.microtick() - start_time;
|
||||
do_many_cycles_count++;
|
||||
}
|
||||
|
||||
//this.coverage_logger.log_end();
|
||||
};
|
||||
|
||||
/** @export */
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
* @constructor
|
||||
* @param {Object=} wm
|
||||
* @param {Object=} codegen
|
||||
* @param {Object=} coverage_logger
|
||||
*/
|
||||
function v86(bus, wm, codegen, coverage_logger)
|
||||
function v86(bus, wm, codegen)
|
||||
{
|
||||
/** @type {boolean} */
|
||||
this.running = false;
|
||||
|
@ -15,7 +14,7 @@ function v86(bus, wm, codegen, coverage_logger)
|
|||
this.stopped = false;
|
||||
|
||||
/** @type {CPU} */
|
||||
this.cpu = new CPU(bus, wm, codegen, coverage_logger);
|
||||
this.cpu = new CPU(bus, wm, codegen);
|
||||
|
||||
this.bus = bus;
|
||||
bus.register("cpu-init", this.init, this);
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const Buffer = require("buffer").Buffer;
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const assert = require("assert");
|
||||
|
||||
const DATA_PATH = path.join(__dirname, "..", "..", "build", "coverage");
|
||||
const REPORT_PATH = path.join(__dirname, "build");
|
||||
|
||||
const data_regex = /^coverage_data_(.*)_([0-9]+)$/;
|
||||
const data_files = fs.readdirSync(DATA_PATH);
|
||||
const report_files = fs.readdirSync(REPORT_PATH);
|
||||
const report_regex = /^report_([0-9]+)$/;
|
||||
const report_num = report_files.filter(name => {
|
||||
// Only report_* files
|
||||
return report_regex.test(name);
|
||||
}).map(
|
||||
// report_{0,1} -> [0,1]
|
||||
report => Number(report.match(report_regex)[1])
|
||||
).reduce(
|
||||
// reduce to max report_num (1 in example), defaulting to 0
|
||||
(a, b) => (a > b ? a : b),
|
||||
0
|
||||
);
|
||||
|
||||
const first_report = report_num === 0;
|
||||
const prev_report_file = path.join(REPORT_PATH, `report_${report_num}`);
|
||||
const prev_report_compare = path.join(REPORT_PATH, `report_{${report_num},${report_num + 1}}`);
|
||||
const report_file = path.join(REPORT_PATH, `report_${report_num + 1}`);
|
||||
|
||||
const raw_json_file = path.join(REPORT_PATH, "all_raw.json");
|
||||
|
||||
if(!first_report)
|
||||
{
|
||||
// May fail if parsed Number != text number, such as report_001 vs. report_1
|
||||
assert.ok(
|
||||
fs.existsSync(prev_report_file),
|
||||
`Report filename format inconsistent. Expected latest: ${prev_report_file}`
|
||||
);
|
||||
}
|
||||
|
||||
let count_fns = 0;
|
||||
const all_data = [];
|
||||
|
||||
for(let file of data_files)
|
||||
{
|
||||
const data_filename_fmt = file.match(data_regex);
|
||||
if(!data_filename_fmt || data_filename_fmt.length !== 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
count_fns++;
|
||||
const data = {
|
||||
fn_name: data_filename_fmt[1],
|
||||
total_blocks: Number(data_filename_fmt[2]),
|
||||
untouched: [],
|
||||
};
|
||||
|
||||
// When old coverage_data is not deleted, and the number of conditional blocks in a function change,
|
||||
// this may trigger
|
||||
assert.ok(!all_data.find(elem => elem.fn_name === data.fn_name), `Function from ${file} seen already`);
|
||||
all_data.push(data);
|
||||
|
||||
const buffer = fs.readFileSync(path.join(DATA_PATH, file));
|
||||
for(let block_index = 0; block_index < data.total_blocks; block_index++)
|
||||
{
|
||||
if(buffer.indexOf(block_index) === -1)
|
||||
{
|
||||
assert.ok(block_index !== 0, `0th block untouched in ${file}`);
|
||||
data.untouched.push(block_index);
|
||||
}
|
||||
}
|
||||
|
||||
// llvm logs the 0th block (function entry), which we don't want to consider
|
||||
// XXX: The 0th block also implies an `else` block sometimes, which we miss
|
||||
data.total_blocks--;
|
||||
|
||||
const touched = data.total_blocks - data.untouched.length;
|
||||
const total = data.total_blocks;
|
||||
const untouched = data.untouched.length;
|
||||
const percent = total === 0 ? 100 : (touched / total * 100).toFixed(0);
|
||||
const log_str = `${percent}% | ${touched} / ${total}\ttouched in ${data.fn_name}; ` +
|
||||
`untouched: ${data.untouched}\n`;
|
||||
|
||||
fs.appendFileSync(report_file, log_str);
|
||||
}
|
||||
fs.writeFileSync(raw_json_file, JSON.stringify(all_data));
|
||||
|
||||
assert.ok(count_fns > 0, "No coverage data files found");
|
||||
|
||||
console.log("[+] Writing to", report_file);
|
||||
console.log("[+] Total functions:", count_fns);
|
||||
console.log("[+] Helpful commands:");
|
||||
|
||||
console.log(`\tsort -n ${report_file} | less`);
|
||||
if(!first_report)
|
||||
{
|
||||
console.log(`\tgit diff --no-index ${prev_report_compare}`);
|
||||
}
|
Loading…
Reference in a new issue