spec: refactor to a dedicated directory
This commit is contained in:
25
src/spec/benchData.ts
Normal file
25
src/spec/benchData.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export interface HaveSPECObjects {
|
||||||
|
objectNames: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SPECBenchData {
|
||||||
|
num: number;
|
||||||
|
name: string;
|
||||||
|
exe: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function benchpath(specdir: string, bench: SPECBenchData): string {
|
||||||
|
return path.join(specdir, 'benchspec', 'CPU', `${bench.num}.${bench.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exepath(specdir: string, bench: SPECBenchData): string {
|
||||||
|
const benchmarkDir = benchpath(specdir, bench);
|
||||||
|
return path.join(benchmarkDir, 'exe', bench.exe);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildpath(specdir: string, bench: SPECBenchData): string {
|
||||||
|
const benchmarkDir = benchpath(specdir, bench);
|
||||||
|
return path.join(benchmarkDir, 'build');
|
||||||
|
}
|
||||||
178
src/spec/index.ts
Normal file
178
src/spec/index.ts
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { promisify } from "util";
|
||||||
|
import { ChildProcessByStdio } from 'child_process';
|
||||||
|
import { Readable, Writable } from 'stream';
|
||||||
|
import { createInterface } from 'readline';
|
||||||
|
import { projectRoot } from 'lyc/environment';
|
||||||
|
import { SPECBenchData, benchpath, buildpath, exepath } from './benchData';
|
||||||
|
|
||||||
|
export{ pop2 } from './pop2';
|
||||||
|
|
||||||
|
|
||||||
|
export function getEnvironment(specdir: string): NodeJS.ProcessEnv {
|
||||||
|
return {
|
||||||
|
...process.env,
|
||||||
|
SPEC: specdir,
|
||||||
|
PATH: `${path.join(specdir, 'bin')}${path.delimiter}${process.env.PATH}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SPEC {
|
||||||
|
newConfig: (name: string, content: string) => Promise<void>;
|
||||||
|
benchpath: (bench: SPECBenchData) => string;
|
||||||
|
exepath: (bench: SPECBenchData) => string;
|
||||||
|
buildpath: (bench: SPECBenchData) => string;
|
||||||
|
getEnvironment: () => NodeJS.ProcessEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mkSPEC(specRoot: string): SPEC {
|
||||||
|
return {
|
||||||
|
newConfig: async (name: string, content: string) => {
|
||||||
|
await writeFile(path.join(specRoot, "config", name), content);
|
||||||
|
},
|
||||||
|
benchpath: bench => benchpath(specRoot, bench),
|
||||||
|
exepath: bench => exepath(specRoot, bench),
|
||||||
|
buildpath: bench => buildpath(specRoot, bench),
|
||||||
|
getEnvironment: () => getEnvironment(specRoot),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Bench {
|
||||||
|
benchpath: () => string;
|
||||||
|
exepath: () => string;
|
||||||
|
buildpath: () => string;
|
||||||
|
benchData: () => SPECBenchData;
|
||||||
|
spec: () => SPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function mkBench(spec: SPEC, bench: SPECBenchData): Bench {
|
||||||
|
return {
|
||||||
|
benchpath: () => spec.benchpath(bench),
|
||||||
|
exepath: () => spec.exepath(bench),
|
||||||
|
buildpath: () => spec.buildpath(bench),
|
||||||
|
benchData: () => bench,
|
||||||
|
spec: () => spec,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const specTemplate = fs.readFileSync(path.resolve(projectRoot, "assets", "specTemplate.cfg")).toString("utf-8");
|
||||||
|
|
||||||
|
const writeFile = promisify(fs.writeFile);
|
||||||
|
|
||||||
|
export interface ConfigOptions {
|
||||||
|
gccdir: string;
|
||||||
|
optimize: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderConfig(options: ConfigOptions) {
|
||||||
|
return `# Rendered from TypeScript ${new Date().toLocaleString()}, do not edit!\n\n\n` + specTemplate
|
||||||
|
.replace("@@GCCDIR@@", options.gccdir)
|
||||||
|
.replace("@@OPTIMIZE@@", options.optimize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface SPECResult {
|
||||||
|
outputFiles: { [key: string]: string[], };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitor SPEC2017 runcpu process in a subprocess.
|
||||||
|
*/
|
||||||
|
export async function watchSPEC<T extends ChildProcessByStdio<null | Writable, Readable, Readable>>(process: T) {
|
||||||
|
const rl = createInterface({
|
||||||
|
input: process.stdout,
|
||||||
|
terminal: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Match & extract string like " format CSV -> /path/to/csv"
|
||||||
|
const formatRe = /^\s*format:\s*(\w+)\s*->\s*(.*)$/;
|
||||||
|
|
||||||
|
return await new Promise<SPECResult>((resolve, reject) => {
|
||||||
|
let outputFiles: { [key: string]: string[]; } = {};
|
||||||
|
rl.on("line", line => {
|
||||||
|
let match;
|
||||||
|
if ((match = formatRe.exec(line)) != null) {
|
||||||
|
const type = match[1];
|
||||||
|
const paths = match[2].split(',').map(path => path.trim());
|
||||||
|
outputFiles[type] = paths;
|
||||||
|
}
|
||||||
|
// To match if the line contains: "runcpu finished
|
||||||
|
if (line.startsWith("runcpu finished")) {
|
||||||
|
resolve({
|
||||||
|
outputFiles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
process.on("error", error => reject(error));
|
||||||
|
process.on("close", () => resolve({
|
||||||
|
outputFiles
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SPECResultsTable {
|
||||||
|
baseThreads: string,
|
||||||
|
baseRuntime: string,
|
||||||
|
baseRatio: string,
|
||||||
|
BaseSelected: string,
|
||||||
|
baseStatus: string,
|
||||||
|
peakThreads: string,
|
||||||
|
peakRuntime: string,
|
||||||
|
peakRatio: string,
|
||||||
|
peakSelected: string,
|
||||||
|
peakStatus: string,
|
||||||
|
description?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseSPECCSVResultsTable(data: string) {
|
||||||
|
const lines = data.split("\n");
|
||||||
|
let index = 0;
|
||||||
|
const eof = () => index >= lines.length;
|
||||||
|
|
||||||
|
let results: { [key: string]: SPECResultsTable; } = {};
|
||||||
|
while (!eof()) {
|
||||||
|
const line = lines[index];
|
||||||
|
if (line.startsWith('"Full Results Table"')) {
|
||||||
|
index += 3;
|
||||||
|
// "Full Results Table"
|
||||||
|
|
||||||
|
// Benchmark,"Base # Threads","Est. Base Run Time","Est. Base Ratio","Base Selected","Base Status","Peak # Threads","Est. Peak Run Time","Est. Peak Ratio","Peak Selected","Peak Status",Description
|
||||||
|
// 600.perlbench_s,1,65.357247,--,0,VE,,,,,,"test iteration #1"
|
||||||
|
// 602.gcc_s,,,,,NR,,,,,NR
|
||||||
|
// 605.mcf_s,,,,,NR,,,,,NR
|
||||||
|
// 620.omnetpp_s,,,,,NR,,,,,NR
|
||||||
|
// 623.xalancbmk_s,,,,,NR,,,,,NR
|
||||||
|
// 625.x264_s,,,,,NR,,,,,NR
|
||||||
|
// 631.deepsjeng_s,,,,,NR,,,,,NR
|
||||||
|
// 641.leela_s,,,,,NR,,,,,NR
|
||||||
|
// 648.exchange2_s,,,,,NR,,,,,NR
|
||||||
|
// 657.xz_s,,,,,NR,,,,,NR
|
||||||
|
while (!eof()) {
|
||||||
|
const dataLine = lines[index];
|
||||||
|
if (dataLine.length == 0)
|
||||||
|
break;
|
||||||
|
const fields: (keyof SPECResultsTable)[] = [
|
||||||
|
"baseThreads",
|
||||||
|
"baseRuntime",
|
||||||
|
"baseRatio",
|
||||||
|
"BaseSelected",
|
||||||
|
"baseStatus",
|
||||||
|
"peakThreads",
|
||||||
|
"peakRuntime",
|
||||||
|
"peakRatio",
|
||||||
|
"peakSelected",
|
||||||
|
"peakStatus",
|
||||||
|
"description",
|
||||||
|
];
|
||||||
|
const splitted = dataLine.split(",");
|
||||||
|
const entries: [keyof SPECResultsTable, string][] = splitted.slice(1).map((name, index) => [fields[index], name]);
|
||||||
|
results[splitted[0]] = (Object.fromEntries(entries) as { [K in keyof SPECResultsTable]: string });
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
@@ -1,19 +1,6 @@
|
|||||||
import * as path from 'path';
|
import { HaveSPECObjects, SPECBenchData } from "./benchData";
|
||||||
import * as fs from "fs";
|
|
||||||
import { promisify } from "util";
|
|
||||||
import { ChildProcessByStdio } from 'child_process';
|
|
||||||
import { Readable, Writable } from 'stream';
|
|
||||||
import { createInterface } from 'readline';
|
|
||||||
import { projectRoot } from './environment';
|
|
||||||
|
|
||||||
export interface SPECBenchData {
|
export const pop2: SPECBenchData & HaveSPECObjects = {
|
||||||
objectNames: string[];
|
|
||||||
num: number;
|
|
||||||
name: string;
|
|
||||||
exe: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const pop2: SPECBenchData = {
|
|
||||||
objectNames: [
|
objectNames: [
|
||||||
"netcdf/attr.o",
|
"netcdf/attr.o",
|
||||||
"netcdf/dim.o",
|
"netcdf/dim.o",
|
||||||
@@ -342,185 +329,3 @@ export const pop2: SPECBenchData = {
|
|||||||
name: "pop2_s",
|
name: "pop2_s",
|
||||||
num: 628,
|
num: 628,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export function benchpath(specdir: string, bench: SPECBenchData): string {
|
|
||||||
return path.join(specdir, 'benchspec', 'CPU', `${bench.num}.${bench.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function exepath(specdir: string, bench: SPECBenchData): string {
|
|
||||||
const benchmarkDir = benchpath(specdir, bench);
|
|
||||||
return path.join(benchmarkDir, 'exe', bench.exe);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildpath(specdir: string, bench: SPECBenchData): string {
|
|
||||||
const benchmarkDir = benchpath(specdir, bench);
|
|
||||||
return path.join(benchmarkDir, 'build');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEnvironment(specdir: string): NodeJS.ProcessEnv {
|
|
||||||
return {
|
|
||||||
...process.env,
|
|
||||||
SPEC: specdir,
|
|
||||||
PATH: `${path.join(specdir, 'bin')}${path.delimiter}${process.env.PATH}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SPEC {
|
|
||||||
newConfig: (name: string, content: string) => Promise<void>;
|
|
||||||
benchpath: (bench: SPECBenchData) => string;
|
|
||||||
exepath: (bench: SPECBenchData) => string;
|
|
||||||
buildpath: (bench: SPECBenchData) => string;
|
|
||||||
getEnvironment: () => NodeJS.ProcessEnv;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mkSPEC(specRoot: string): SPEC {
|
|
||||||
return {
|
|
||||||
newConfig: async (name: string, content: string) => {
|
|
||||||
await writeFile(path.join(specRoot, "config", name), content);
|
|
||||||
},
|
|
||||||
benchpath: bench => benchpath(specRoot, bench),
|
|
||||||
exepath: bench => exepath(specRoot, bench),
|
|
||||||
buildpath: bench => buildpath(specRoot, bench),
|
|
||||||
getEnvironment: () => getEnvironment(specRoot),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Bench {
|
|
||||||
benchpath: () => string;
|
|
||||||
exepath: () => string;
|
|
||||||
buildpath: () => string;
|
|
||||||
benchData: () => SPECBenchData;
|
|
||||||
spec: () => SPEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function mkBench(spec: SPEC, bench: SPECBenchData): Bench {
|
|
||||||
return {
|
|
||||||
benchpath: () => spec.benchpath(bench),
|
|
||||||
exepath: () => spec.exepath(bench),
|
|
||||||
buildpath: () => spec.buildpath(bench),
|
|
||||||
benchData: () => bench,
|
|
||||||
spec: () => spec,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const specTemplate = fs.readFileSync(path.resolve(projectRoot, "assets", "specTemplate.cfg")).toString("utf-8");
|
|
||||||
|
|
||||||
const writeFile = promisify(fs.writeFile);
|
|
||||||
|
|
||||||
export interface ConfigOptions {
|
|
||||||
gccdir: string;
|
|
||||||
optimize: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderConfig(options: ConfigOptions) {
|
|
||||||
return `# Rendered from TypeScript ${new Date().toLocaleString()}, do not edit!\n\n\n` + specTemplate
|
|
||||||
.replace("@@GCCDIR@@", options.gccdir)
|
|
||||||
.replace("@@OPTIMIZE@@", options.optimize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface SPECResult {
|
|
||||||
outputFiles: { [key: string]: string[], };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitor SPEC2017 runcpu process in a subprocess.
|
|
||||||
*/
|
|
||||||
export async function watchSPEC<T extends ChildProcessByStdio<null | Writable, Readable, Readable>>(process: T) {
|
|
||||||
const rl = createInterface({
|
|
||||||
input: process.stdout,
|
|
||||||
terminal: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Match & extract string like " format CSV -> /path/to/csv"
|
|
||||||
const formatRe = /^\s*format:\s*(\w+)\s*->\s*(.*)$/;
|
|
||||||
|
|
||||||
return await new Promise<SPECResult>((resolve, reject) => {
|
|
||||||
let outputFiles: { [key: string]: string[]; } = {};
|
|
||||||
rl.on("line", line => {
|
|
||||||
let match;
|
|
||||||
if ((match = formatRe.exec(line)) != null) {
|
|
||||||
const type = match[1];
|
|
||||||
const paths = match[2].split(',').map(path => path.trim());
|
|
||||||
outputFiles[type] = paths;
|
|
||||||
}
|
|
||||||
// To match if the line contains: "runcpu finished
|
|
||||||
if (line.startsWith("runcpu finished")) {
|
|
||||||
resolve({
|
|
||||||
outputFiles
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
process.on("error", error => reject(error));
|
|
||||||
process.on("close", () => resolve({
|
|
||||||
outputFiles
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SPECResultsTable {
|
|
||||||
baseThreads: string,
|
|
||||||
baseRuntime: string,
|
|
||||||
baseRatio: string,
|
|
||||||
BaseSelected: string,
|
|
||||||
baseStatus: string,
|
|
||||||
peakThreads: string,
|
|
||||||
peakRuntime: string,
|
|
||||||
peakRatio: string,
|
|
||||||
peakSelected: string,
|
|
||||||
peakStatus: string,
|
|
||||||
description?: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseSPECCSVResultsTable(data: string) {
|
|
||||||
const lines = data.split("\n");
|
|
||||||
let index = 0;
|
|
||||||
const eof = () => index >= lines.length;
|
|
||||||
|
|
||||||
let results: { [key: string]: SPECResultsTable; } = {};
|
|
||||||
while (!eof()) {
|
|
||||||
const line = lines[index];
|
|
||||||
if (line.startsWith('"Full Results Table"')) {
|
|
||||||
index += 3;
|
|
||||||
// "Full Results Table"
|
|
||||||
|
|
||||||
// Benchmark,"Base # Threads","Est. Base Run Time","Est. Base Ratio","Base Selected","Base Status","Peak # Threads","Est. Peak Run Time","Est. Peak Ratio","Peak Selected","Peak Status",Description
|
|
||||||
// 600.perlbench_s,1,65.357247,--,0,VE,,,,,,"test iteration #1"
|
|
||||||
// 602.gcc_s,,,,,NR,,,,,NR
|
|
||||||
// 605.mcf_s,,,,,NR,,,,,NR
|
|
||||||
// 620.omnetpp_s,,,,,NR,,,,,NR
|
|
||||||
// 623.xalancbmk_s,,,,,NR,,,,,NR
|
|
||||||
// 625.x264_s,,,,,NR,,,,,NR
|
|
||||||
// 631.deepsjeng_s,,,,,NR,,,,,NR
|
|
||||||
// 641.leela_s,,,,,NR,,,,,NR
|
|
||||||
// 648.exchange2_s,,,,,NR,,,,,NR
|
|
||||||
// 657.xz_s,,,,,NR,,,,,NR
|
|
||||||
while (!eof()) {
|
|
||||||
const dataLine = lines[index];
|
|
||||||
if (dataLine.length == 0)
|
|
||||||
break;
|
|
||||||
const fields: (keyof SPECResultsTable)[] = [
|
|
||||||
"baseThreads",
|
|
||||||
"baseRuntime",
|
|
||||||
"baseRatio",
|
|
||||||
"BaseSelected",
|
|
||||||
"baseStatus",
|
|
||||||
"peakThreads",
|
|
||||||
"peakRuntime",
|
|
||||||
"peakRatio",
|
|
||||||
"peakSelected",
|
|
||||||
"peakStatus",
|
|
||||||
"description",
|
|
||||||
];
|
|
||||||
const splitted = dataLine.split(",");
|
|
||||||
const entries: [keyof SPECResultsTable, string][] = splitted.slice(1).map((name, index) => [fields[index], name]);
|
|
||||||
results[splitted[0]] = (Object.fromEntries(entries) as { [K in keyof SPECResultsTable]: string });
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user