/** * 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; } 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]); })();