272 lines
9.1 KiB
TypeScript
272 lines
9.1 KiB
TypeScript
/**
|
|
* Binary search the first bad object in object sets.
|
|
* Things todo:
|
|
* 1. Determine the set of vector, or scalar version.
|
|
* 2. Use the mechanism above, construct such set
|
|
* 3. Link the set to an executable -> SPEC path, invoke "runcpu"
|
|
*/
|
|
|
|
import { binSearch } from "./algorithm";
|
|
import { pop2, SPEC, Bench, mkBench, mkSPEC } from "./spec";
|
|
import path from "path";
|
|
import { FLANG, PREFIX, SW_AUTOVEC, SYSROOT_PREFIX } from "./environment";
|
|
import { generalCommand, linkerCommand } from "./commands/compiler";
|
|
import { runcpuOptions } from "./commands/spec";
|
|
import { checkedSpawnSync, promisifySpawn } from "./cli";
|
|
import { systemdRunOptions } from "./commands/systemd";
|
|
import { spawn } from "child_process";
|
|
|
|
export interface Linkable {
|
|
link: (objectPath: (objectNames: string[]) => string[]) => Promise<void>;
|
|
}
|
|
|
|
function mkPop2Bench(spec: SPEC): Bench & Linkable {
|
|
const base = mkBench(spec, pop2);
|
|
return {
|
|
...base,
|
|
async link(objectPath) {
|
|
// Set up environment variables.
|
|
// FIXME: use -rpath or -rpath-link after I find out why.
|
|
const objects = objectPath(base.benchData().objectNames);
|
|
|
|
const options = [
|
|
...objects,
|
|
...linkerCommand({
|
|
searchDirs: [path.join(PREFIX, "lib"),],
|
|
}),
|
|
...generalCommand({
|
|
output: base.exepath(),
|
|
outputKind: "exe",
|
|
sysroot: SYSROOT_PREFIX,
|
|
}),
|
|
];
|
|
|
|
// Execute the link command
|
|
const proc = checkedSpawnSync(FLANG, options, {
|
|
stdio: "inherit",
|
|
env: {
|
|
...process.env,
|
|
LD_LIBRARY_PATH: [
|
|
path.join(PREFIX, 'lib'),
|
|
path.join(SYSROOT_PREFIX, 'lib'),
|
|
path.join(SYSROOT_PREFIX, 'usr', 'lib')
|
|
].join(':')
|
|
},
|
|
});
|
|
|
|
if (proc.error) {
|
|
throw proc.error;
|
|
}
|
|
},
|
|
};
|
|
}
|
|
|
|
|
|
// Bisect results.
|
|
|
|
const beforeHalfGrid = [
|
|
// 0.336
|
|
|
|
// Scalar [0, 161): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.671.fpspeed.refspeed.txt
|
|
// : /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.664.fpspeed.refspeed.txt
|
|
// Scalar [161, 322): Correct.
|
|
|
|
false,
|
|
// Scalar [161, 241): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.672.fpspeed.refspeed.txt
|
|
// Scalar [241, 322): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017-2/result/CPU2017.672.fpspeed.refspeed.rsf
|
|
// Vector [161, 241): Error,
|
|
// Vector [241, 322): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017-2/result/CPU2017.673.fpspeed.refspeed.txt
|
|
|
|
false,
|
|
// Vector [241, 281): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.674.fpspeed.refspeed.txt
|
|
// Vector [281, 322): Correct.
|
|
|
|
true,
|
|
// Vector [241, 261): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.675.fpspeed.refspeed.rsf
|
|
// Vector [261, 281): Correct.
|
|
|
|
true,
|
|
// Vector [241, 251): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.676.fpspeed.refspeed.txt
|
|
// Vector [251, 261): Stopped.
|
|
|
|
true,
|
|
// Vector [241, 246): Error,
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.677.fpspeed.refspeed.rsf
|
|
];
|
|
|
|
const beforeHalfNoGrid: boolean[] = [
|
|
false,
|
|
|
|
// Vector [161, 241): Error
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.679.
|
|
// Vector [241, 322): Unknown
|
|
true,
|
|
|
|
// Vector [161, 201): Unknown
|
|
// Vector [201, 241): Error
|
|
false,
|
|
|
|
// Vector [201, 221): Error
|
|
// /home/lyc/workspace/sw-autovec/spec2017/result/CPU2017.681
|
|
// Vector [221, 241): Unknown
|
|
true,
|
|
|
|
// Vector [201, 211): Error
|
|
// Vector [211, 221): Unknown
|
|
true,
|
|
|
|
// Vector [201, 206): Unknown
|
|
// Vector [206, 211): Error
|
|
false,
|
|
|
|
// Vector [206, 208): Error
|
|
// Vector [208, 211): ?
|
|
true,
|
|
|
|
// Vector [206, 207): ?
|
|
// !!! Vector [207, 208): Error
|
|
];
|
|
|
|
async function bisect(
|
|
beforeHalf: boolean[],
|
|
/** specify which spec to use */
|
|
rangeSPEC: (range: [number, number], index: number) => SPEC,
|
|
/** How to get the vector object path */
|
|
vector: (name: string) => string,
|
|
/** And how to get scalar path. */
|
|
scalar: (name: string) => string,
|
|
) {
|
|
const [vBegin, vHalf, vEnd] = binSearch(0, pop2.objectNames.length, beforeHalf);
|
|
|
|
// use scalar version if index is in this range.
|
|
const vectorRange: [number, number][] = [
|
|
[vBegin, vHalf],
|
|
[vHalf, vEnd],
|
|
];
|
|
|
|
await Promise.all(vectorRange.map((range, index) => ({
|
|
range,
|
|
// Assign each range a dedicated SPEC, to avoid race conditions.
|
|
spec: rangeSPEC(range, index),
|
|
})).map(async ({ range, spec }) => {
|
|
// For each range, linking the objects and test it.
|
|
|
|
const [a, b] = range;
|
|
|
|
const pop2Bench = mkPop2Bench(spec);
|
|
|
|
console.log(`Linking objects. Range in [${a}, ${b}) used vector version. others are scalar version.`);
|
|
await pop2Bench.link(names =>
|
|
names.map((name, index) => {
|
|
if (name === "grid.fppized.o" || index == 207) {
|
|
console.log(`${name} is a bad object!`);
|
|
return scalar(name);
|
|
}
|
|
// If index is in range [a, b), use the vector version.
|
|
return a <= index && index < b ? vector(name) : scalar(name);
|
|
}));
|
|
|
|
const serviceName = `${pop2Bench.benchData().num}-${a}-${b}`;
|
|
|
|
checkedSpawnSync("systemd-run",
|
|
[
|
|
...systemdRunOptions({
|
|
scope: false,
|
|
unit: `spec-${serviceName}`,
|
|
user: true,
|
|
}),
|
|
"runcpu",
|
|
...runcpuOptions({
|
|
benchmarks: [pop2Bench.benchData().num.toString()],
|
|
config: "clang-O2.cfg",
|
|
workload: "ref",
|
|
buildType: "nobuild",
|
|
outputFormat: ["text", "config"]
|
|
}),
|
|
], { stdio: "inherit", env: spec.getEnvironment() });
|
|
}));
|
|
};
|
|
|
|
(async () => {
|
|
|
|
const buildPathObj = (buildBase: string) => (build: string) => (objname: string) => path.join(buildBase, build, objname);
|
|
const buildDirs = ["build_vector", "build_scalar_vanilla"];
|
|
|
|
const specs = [
|
|
"spec2017",
|
|
"spec2017-2",
|
|
].map(s => path.resolve(SW_AUTOVEC, s)).map(mkSPEC);
|
|
|
|
// To test which version works, for grid.
|
|
await (async (spec: SPEC) => {
|
|
const pop2Bench = mkPop2Bench(spec);
|
|
|
|
const [vector, scalar] = buildDirs.map(dir => buildPathObj(spec.buildpath(pop2))(dir));
|
|
|
|
await pop2Bench.link(names => {
|
|
return names.flatMap(p => {
|
|
if (p == "grid.fppized.o") {
|
|
const functionList = [
|
|
"grid_.o",
|
|
"grid_area_masks_.o",
|
|
"grid_calc_tpoints_.o",
|
|
"grid_cf_area_avg_.o",
|
|
"grid_compute_dz_.o",
|
|
"grid_fill_points_.o",
|
|
"grid_horiz_grid_internal_.o",
|
|
"grid_init_grid1_.o",
|
|
"grid_init_grid2_.o",
|
|
"grid_landmasks_.o",
|
|
"grid_read_bottom_cell_.o",
|
|
"grid_read_horiz_grid_.o",
|
|
"grid_read_topography_.o",
|
|
"grid_read_vert_grid_.o",
|
|
"grid_remove_isolated_points_.o",
|
|
"grid_remove_points_.o",
|
|
"grid_smooth_topography_.o",
|
|
"grid_tgrid_to_ugrid_.o",
|
|
"grid_topography_bathymetry_.o",
|
|
"grid_topography_internal_.o",
|
|
"grid_ugrid_to_tgrid_.o",
|
|
"grid_vert_grid_internal_.o",
|
|
];
|
|
return [
|
|
...functionList.map(fn => {
|
|
const getFunc = (name: string) => path.join(spec.buildpath(pop2), name, fn);
|
|
return fn == "grid_landmasks_.o" ? getFunc("function_scalar") : getFunc("function_simd");
|
|
}),
|
|
path.join(spec.buildpath(pop2), "global-obj.ll.o")
|
|
];
|
|
}
|
|
return vector(p);
|
|
});
|
|
});
|
|
|
|
await promisifySpawn(spawn("systemd-run",
|
|
[
|
|
...systemdRunOptions({
|
|
scope: true,
|
|
user: true,
|
|
unit: "pop2-grid-test",
|
|
}),
|
|
"runcpu",
|
|
...runcpuOptions({
|
|
benchmarks: [pop2Bench.benchData().num.toString()],
|
|
config: "clang-O2",
|
|
workload: "test",
|
|
buildType: "nobuild",
|
|
outputFormat: ["text", "config"]
|
|
}),
|
|
], { stdio: "inherit", env: spec.getEnvironment() }));
|
|
|
|
})(specs[0]);
|
|
|
|
})();
|