mix-object: add functions bisect
This commit is contained in:
@@ -7,14 +7,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { binSearch } from "./algorithm";
|
import { binSearch } from "./algorithm";
|
||||||
import { pop2, SPEC, Bench, mkBench, mkSPEC } from "./spec";
|
import { pop2, SPEC, Bench, mkBench, mkSPEC, defaultSPEC, watchSPEC, parseSPECCSVResultsTable } from "./spec";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { FLANG, PREFIX, SW_AUTOVEC, SYSROOT_PREFIX } from "./environment";
|
import { FLANG, LLVM_EXTRACT, PREFIX, SW_AUTOVEC, SYSROOT_PREFIX, projectRoot } from "./environment";
|
||||||
import { generalCommand, linkerCommand } from "./commands/compiler";
|
import { extractCommand, generalCommand, linkerCommand } from "./commands/compiler";
|
||||||
import { runcpuOptions } from "./commands/spec";
|
import { runcpuOptions } from "./commands/spec";
|
||||||
import { checkedSpawnSync, promisifySpawn } from "./cli";
|
import { checkedSpawnSync, promisifySpawn } from "./cli";
|
||||||
import { systemdRunOptions } from "./commands/systemd";
|
import { systemdRunOptions } from "./commands/systemd";
|
||||||
import { spawn } from "child_process";
|
import { spawn } from "child_process";
|
||||||
|
import { functionList } from "./llvm-parser";
|
||||||
|
import assert from "assert";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
export interface Linkable {
|
export interface Linkable {
|
||||||
link: (objectPath: (objectNames: string[]) => string[]) => Promise<void>;
|
link: (objectPath: (objectNames: string[]) => string[]) => Promise<void>;
|
||||||
@@ -194,10 +198,10 @@ async function bisect(
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
(async () => {
|
const buildPathObj = (buildBase: string) => (build: string) => (objname: string) => path.join(buildBase, build, objname);
|
||||||
|
const buildDirs = ["build_vector", "build_scalar_vanilla"];
|
||||||
|
|
||||||
const buildPathObj = (buildBase: string) => (build: string) => (objname: string) => path.join(buildBase, build, objname);
|
async function verifyGridFunction() {
|
||||||
const buildDirs = ["build_vector", "build_scalar_vanilla"];
|
|
||||||
|
|
||||||
const specs = [
|
const specs = [
|
||||||
"spec2017",
|
"spec2017",
|
||||||
@@ -268,4 +272,211 @@ async function bisect(
|
|||||||
|
|
||||||
})(specs[0]);
|
})(specs[0]);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
// It is known that object index == 207 is also wrong for pop2.
|
||||||
|
|
||||||
|
const spec = defaultSPEC;
|
||||||
|
|
||||||
|
const troubleName = pop2.objectNames[207].replace(/\.o$/, "");
|
||||||
|
|
||||||
|
const pop2bench = mkPop2Bench(spec);
|
||||||
|
|
||||||
|
const local = path.resolve(projectRoot, "local");
|
||||||
|
|
||||||
|
// Maps from name of function -> path to object file.
|
||||||
|
const localSuffix = (suffix: string) => (fn: string) => path.resolve(local, `${fn}-${suffix}.o`);
|
||||||
|
const vectorObject = localSuffix("vector");
|
||||||
|
const scalarObject = localSuffix("scalar");
|
||||||
|
|
||||||
|
const build = path.resolve(spec.buildpath(pop2), "build_vector_test");
|
||||||
|
|
||||||
|
// Compile that object to "ll"
|
||||||
|
async function compileIR() {
|
||||||
|
const llvmIR = spawn(FLANG, ([
|
||||||
|
...generalCommand({
|
||||||
|
outputKind: "assembly",
|
||||||
|
output: "-",
|
||||||
|
sysroot: SYSROOT_PREFIX,
|
||||||
|
}),
|
||||||
|
"-emit-llvm",
|
||||||
|
"-O2",
|
||||||
|
"-msimd",
|
||||||
|
"-Mbyteswapio",
|
||||||
|
"-fno-discard-value-names",
|
||||||
|
path.resolve(build, `${troubleName}.f90`),
|
||||||
|
]), { stdio: ['inherit', 'pipe', 'inherit'], cwd: build });
|
||||||
|
|
||||||
|
const chunks: Buffer[] = [];
|
||||||
|
|
||||||
|
llvmIR.stdout.on("data", chunk => { chunks.push(Buffer.from(chunk)); });
|
||||||
|
|
||||||
|
const llvmIRResult = await promisifySpawn(llvmIR);
|
||||||
|
llvmIRResult.stdout;
|
||||||
|
|
||||||
|
return Buffer.concat(chunks).toString("utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const objFlags = [
|
||||||
|
...generalCommand({
|
||||||
|
outputKind: "object",
|
||||||
|
}),
|
||||||
|
"-x", "ir",
|
||||||
|
// Read from stdin.
|
||||||
|
"-",
|
||||||
|
];
|
||||||
|
|
||||||
|
const IR = await compileIR();
|
||||||
|
|
||||||
|
// First prepare a functions dir that would be suitable for replacing it's ".o"
|
||||||
|
async function prepareDir(IR: string, vectorObject: (fn: string) => string, scalarObject: (fn: string) => string) {
|
||||||
|
// Parse the IR with all function names
|
||||||
|
|
||||||
|
const fnList = functionList(IR);
|
||||||
|
|
||||||
|
// For each function, extract it.
|
||||||
|
await Promise.all(fnList.map(fn => {
|
||||||
|
const proc = spawn(LLVM_EXTRACT, [
|
||||||
|
...extractCommand({
|
||||||
|
func: [fn],
|
||||||
|
asm: true,
|
||||||
|
input: "-",
|
||||||
|
output: "-",
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Write IR and close stdin
|
||||||
|
proc.stdin.write(IR);
|
||||||
|
proc.stdin.end();
|
||||||
|
|
||||||
|
const compileVector = spawn(FLANG, [
|
||||||
|
...objFlags,
|
||||||
|
...generalCommand({ output: vectorObject(fn), }),
|
||||||
|
"-msimd",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const compileScalar = spawn(FLANG, [
|
||||||
|
...objFlags,
|
||||||
|
...generalCommand({ output: scalarObject(fn) }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
proc.stdout.pipe(compileVector.stdin);
|
||||||
|
proc.stdout.pipe(compileScalar.stdin);
|
||||||
|
|
||||||
|
return Promise.all([proc, compileScalar, compileScalar].map(promisifySpawn));
|
||||||
|
}));
|
||||||
|
|
||||||
|
return fnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fnList = await prepareDir(IR, vectorObject, scalarObject);
|
||||||
|
|
||||||
|
// Also extract global names.
|
||||||
|
const globalObj = path.resolve(local, "207-global.o");
|
||||||
|
await (async () => {
|
||||||
|
const proc = spawn(LLVM_EXTRACT, [
|
||||||
|
...extractCommand({
|
||||||
|
asm: true,
|
||||||
|
input: "-",
|
||||||
|
output: "-",
|
||||||
|
}),
|
||||||
|
// Extract all global variables.
|
||||||
|
"-rglob",
|
||||||
|
".*",
|
||||||
|
], { stdio: ['pipe', 'pipe', 'inherit'] });
|
||||||
|
|
||||||
|
// Write IR and close stdin
|
||||||
|
proc.stdin.write(IR);
|
||||||
|
proc.stdin.end();
|
||||||
|
|
||||||
|
const compileScalar = spawn(FLANG, [
|
||||||
|
...objFlags,
|
||||||
|
...generalCommand({ output: globalObj }),
|
||||||
|
], { stdio: ['pipe', 'inherit', 'inherit'] });
|
||||||
|
|
||||||
|
proc.stdout.pipe(compileScalar.stdin);
|
||||||
|
|
||||||
|
return Promise.all([proc, compileScalar].map(promisifySpawn));
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Bisect with replacing functions.
|
||||||
|
|
||||||
|
const [vector, scalar] = buildDirs.map(dir => buildPathObj(spec.buildpath(pop2))(dir));
|
||||||
|
|
||||||
|
// Run many SPEC2017, with different "outputRoot"
|
||||||
|
for (const fn of fnList) {
|
||||||
|
console.log(`testing function ${fn}`);
|
||||||
|
// For each function, try use a scalar version of that func
|
||||||
|
// Others are vector version.
|
||||||
|
const linkingList = fnList.map(name => name == fn ? scalarObject(name) : vectorObject(name));
|
||||||
|
|
||||||
|
// Link together with other objects.
|
||||||
|
await pop2bench.link(objectNames => objectNames.flatMap((objectName, index) => {
|
||||||
|
if (index == 207) {
|
||||||
|
return [...linkingList, globalObj];
|
||||||
|
}
|
||||||
|
if (objectName == "grid.fppized.o") {
|
||||||
|
return scalar(objectName);
|
||||||
|
}
|
||||||
|
return vector(objectName);
|
||||||
|
}));
|
||||||
|
|
||||||
|
const unitName = `pop2-${fn}-${crypto.randomUUID()}`;
|
||||||
|
// Spawn SPEC process.
|
||||||
|
const runcpu = spawn("systemd-run", [
|
||||||
|
...systemdRunOptions({
|
||||||
|
scope: true,
|
||||||
|
user: true,
|
||||||
|
unit: unitName,
|
||||||
|
}),
|
||||||
|
"runcpu",
|
||||||
|
...runcpuOptions({
|
||||||
|
benchmarks: [pop2.name],
|
||||||
|
buildType: "nobuild",
|
||||||
|
config: "clang-O2",
|
||||||
|
workload: "ref",
|
||||||
|
setprocgroup: true,
|
||||||
|
})
|
||||||
|
], { env: spec.getEnvironment() });
|
||||||
|
|
||||||
|
let OK = false;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!OK) {
|
||||||
|
console.log("timeout, kill the process.");
|
||||||
|
checkedSpawnSync(
|
||||||
|
"systemctl", [
|
||||||
|
"--user",
|
||||||
|
"stop",
|
||||||
|
`${unitName}.scope`,
|
||||||
|
], { stdio: "inherit" }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, 10 * 60 * 1000); // 10min
|
||||||
|
|
||||||
|
|
||||||
|
runcpu.stdout.pipe(process.stdout);
|
||||||
|
runcpu.stderr.pipe(process.stderr);
|
||||||
|
|
||||||
|
const result = await watchSPEC(runcpu);
|
||||||
|
|
||||||
|
OK = true;
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
|
||||||
|
if ("CSV" in result.outputFiles) {
|
||||||
|
assert(result.outputFiles.CSV.length > 0);
|
||||||
|
const Results = parseSPECCSVResultsTable((await fs.readFile(result.outputFiles.CSV[0])).toString("utf-8"));
|
||||||
|
let perlbenchResult;
|
||||||
|
if (perlbenchResult = Results[`${pop2.num}-${pop2.name}`]) {
|
||||||
|
if (perlbenchResult.baseStatus !== "S") {
|
||||||
|
console.log("Error!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("SPEC does not produce CSV output!");
|
||||||
|
}
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user