@specs-feup/clava
Version:
A C/C++ source-to-source compiler written in Typescript
208 lines • 6.77 kB
JavaScript
import Io from "@specs-feup/lara/api/lara/Io.js";
import Strings from "@specs-feup/lara/api/lara/Strings.js";
import JavaTypes from "@specs-feup/lara/api/lara/util/JavaTypes.js";
import Query from "@specs-feup/lara/api/weaver/Query.js";
import { FunctionJp } from "../../Joinpoints.js";
import Clava from "../Clava.js";
import CMaker from "../cmake/CMaker.js";
import { debug } from "@specs-feup/lara/api/lara/core/LaraCore.js";
function GproferGetCxxFunction(signature) {
return Query.search(FunctionJp, {
signature: signature,
hasDefinition: true,
}).first();
}
function GproferGetCFunction(signature) {
return Query.search(FunctionJp, {
name: signature,
hasDefinition: true,
}).first();
}
export default class Gprofer {
_runs;
_args;
_app = Clava.getProgram();
_workingDir = undefined;
_deleteWorkingDir = false;
_checkReturn = true;
_data = {};
_hotSpots = {};
_cmaker = this.defaultCmaker();
_gProfer = JavaTypes.Gprofer;
constructor(runs = 1, args = []) {
this._runs = runs;
this._args = args;
}
getCmaker() {
return this._cmaker;
}
static _EXE_NAME = "gprofer_bin";
defaultCmaker() {
const cmaker = new CMaker(Gprofer._EXE_NAME, false);
if (Clava.isCxx()) {
cmaker.addCxxFlags("-no-pie", "-pg");
}
else {
cmaker.addFlags("-no-pie", "-pg");
}
// sources
for (const $jp of this._app.getDescendants("file")) {
const $file = $jp;
if ($file.isHeader) {
continue;
}
cmaker.getSources().addSource($file.filepath);
}
// includes
for (const obj of Clava.getIncludeFolders()) {
const userInclude = obj;
debug("Adding include: " + userInclude);
cmaker.addIncludeFolder(userInclude);
}
return cmaker;
}
static _buildName($function) {
if (Clava.isCxx()) {
/* signature or qualified name */
return $function.signature;
}
return $function.name;
}
setArgs(args) {
this._args = args;
return this;
}
setRuns(runs) {
this._runs = runs;
return this;
}
setCheckReturn(checkReturn) {
this._checkReturn = checkReturn;
return this;
}
setWorkingDir(workingDir, deleteWorkingDir) {
this._workingDir = Io.getPath(workingDir);
this._deleteWorkingDir = deleteWorkingDir;
return this;
}
profile() {
if (this._workingDir === undefined) {
this._workingDir = Io.getTempFolder("gprofer_" + Strings.uuid());
this._deleteWorkingDir = true;
}
// compile the application
const binary = this._cmaker.build(this._workingDir, Io.getPath(this._workingDir, "build"));
// call java gprofer
const data = this._gProfer.profile(binary, this._args, this._runs, this._workingDir, this._deleteWorkingDir, this._checkReturn);
const json = this._gProfer.getJsonData(data);
// fill this._data and this._hotSpots
const obj = JSON.parse(json);
this._hotSpots = obj.hotspots;
this._data = obj.table;
return this;
}
getHotspotNames() {
return this._hotSpots;
}
writeProfile(path = Io.getPath("./gprofer.json")) {
const profile = {
data: this._data,
hotspots: this._hotSpots,
};
Io.writeJson(path.getAbsolutePath(), profile);
}
readProfile(path = Io.getPath("./gprofer.json")) {
const obj = Io.readJson(path.getAbsolutePath());
this._data = obj.data;
this._hotSpots = obj.hotspots;
}
/**
*
* May return undefined if the desired function is a system or library function and not available in the source code.
* */
getHotspot(rank = 0) {
const _rank = rank;
const signature = this._hotSpots[_rank];
const f = this._getHotspot(signature);
if (f === undefined) {
console.log(`Could not find hotspot with rank ${rank} and signature ${signature}. It may be a system function.\n`);
}
return f;
}
/**
* Internal method that uses the signature to identify a function.
* */
_getHotspot(signature) {
let f = undefined;
if (Clava.isCxx()) {
debug("finding Cxx function with signature " + signature);
f = GproferGetCxxFunction(signature);
}
else {
debug("finding C function with signature " + signature);
f = GproferGetCFunction(signature);
}
return f;
}
getPercentage($function) {
return this.get("percentage", $function);
}
getCalls($function) {
return this.get("calls", $function);
}
getSelfSeconds($function) {
return this.get("selfSeconds", $function);
}
getSelfMsCall($function) {
return this.get("selfMsCall", $function);
}
getTotalMsCall($function) {
return this.get("totalMsCall", $function);
}
get(type, $function) {
const name = Gprofer._buildName($function);
return this._data[name][type];
}
print($function) {
const perc = this.getPercentage($function);
const calls = this.getCalls($function);
const self = this.getSelfSeconds($function);
const selfCall = this.getSelfMsCall($function);
const totalCall = this.getTotalMsCall($function);
console.log($function.signature);
if (perc !== undefined) {
console.log(`\tPercentage: ${perc}%`);
}
if (calls !== undefined) {
console.log(`\tCalls: ${calls}`);
}
if (self !== undefined) {
console.log(`\tSelf seconds: ${self}s`);
}
if (selfCall !== undefined) {
console.log(`\tSelf ms/call: ${selfCall}ms`);
}
if (totalCall !== undefined) {
console.log(`\tTotal ms/call: ${totalCall}ms`);
}
}
removeSystemFunctions() {
const toRemove = [];
for (const index in this._hotSpots) {
const sigIndex = Number(index);
const sig = this._hotSpots[sigIndex];
const $hs = this._getHotspot(sig);
if ($hs === undefined) {
// mark to remove from array
toRemove.push(sigIndex);
// remove from map
delete this._data[sig];
}
}
// remove from array
for (const sigIndex of toRemove) {
delete this._hotSpots[sigIndex];
}
}
}
//# sourceMappingURL=Gprofer.js.map