// Please refer to the COPYRIGHT file of the profiling package for details. // SPDX-License-Identifier: MIT /* * profiling: Line by line profiling and code coverage for GAP
*/
struct JsonParse
{ // Type of line
ProfType Type; // Name of function (for function start/end)
std::string Fun; // Time spent on line int Ticks; // Number of line executed (1 is ommitted from JSON) int Execs; // Line executed int Line; // End line of function (for function start) int EndLine;
std::string File; int FileId;
// We lazily set up 'children' because we can't be bothered using // a shared_ptr struct StackTrace
{ int runtime; int calls;
std::map<FullFunction, StackTrace>* children;
StackTrace* parent;
// prev_exec is the last function executed, calling_exec is the statement which // we would currently say called a function. The only time when there differ // is immediately after returning from a function.
JsonParse prev_exec;
JsonParse calling_exec;
// These keeps track of us going down our function stack
std::vector<FullFunction> function_stack;
std::vector<JsonParse> line_stack; // this stores various time values // when we call a function, so we can correct everything on return.
std::vector<TimeStash> line_times_stack;
longlong total_ticks = 0;
if(!(IS_STRING(filename))) {
ErrorMayQuit("Filename must be a string", 0, 0);
}
Obj filenamestr = CopyToStringRep(filename);
Stream infile(CSTR_STRING(filenamestr)); if(infile.fail()) {
ErrorMayQuit("Unable to open file %s", (Int)CSTR_STRING(filenamestr), 0); return Fail;
}
long line_number = 0;
while(true)
{ if(feof(infile.stream)) { break;
}
line_number++; char str[10000]; if(fgets(str, 10000, infile.stream) == 0)
{ if(feof(infile.stream)) { break;
} else { return Fail;
}
}
JsonParse ret; if(ReadJson(str, ret))
{ switch(ret.Type)
{ case InvalidType: ErrorReturnVoid("Internal Error",0,0,""); break; case StringId: if(filename_map.count(ret.FileId) > 0) {
ErrorMayQuit("Invalid input - Reused fileId. Did you try concatenating files?" "Use ConcatenateLineByLineProfiles",0,0); break;
}
filename_map[ret.FileId] = ret.File;
filename_map_inverse[ret.File] = ret.FileId; break; case IntoFun:
{
FullFunction retfunc = buildFunctionName(ret); // Record which line called this function
called_functions[calling_exec.FileId][calling_exec.Line].insert(retfunc); // Record we called this function from here if(!function_stack.empty()) { // This '!= 0' is to support older GAP's which don't provide this field if(ret.FileId != 0) {
std::string filename = function_stack.back().filename;
calling_functions[ret.FileId][ret.Line].insert(Location(filename, filename_map[calling_exec.FileId], calling_exec.Line));
}
} // Add this function to the stack of executing functions
function_stack.push_back(retfunc);
staticint deepest_depth = 0; if(function_stack.size() > deepest_depth) {
deepest_depth = function_stack.size();
} // And to stack of executed files/line numbers
line_stack.push_back(calling_exec); // We also store the amount of time spent in this stack as well.
line_times_stack.push_back(
TimeStash(runtime_lines[calling_exec.FileId][calling_exec.Line],
runtime_with_children_lines[calling_exec.FileId][calling_exec.Line],
total_ticks));
if(ret.Type == Read)
{
read_lines[ret.FileId].insert(ret.Line);
} else
{
exec_lines[ret.FileId][ret.Line]+=ret.Execs; if(firstExec)
firstExec = false; else
{ // The ticks are since the last executed line if(ret.Ticks > 0) {
runtime_lines[prev_exec.FileId][prev_exec.Line]+=ret.Ticks; // Hard to know exactly where to charge these to -- // this is easiest
(current_stack->runtime) += ret.Ticks;
total_ticks += ret.Ticks;
}
}
} break; case Info:
isCover = ret.IsCover;
timeType = ret.TimeType; break;
}
} else
{ // We allow a few failed parses to deal with truncated files
failedparse++;
Pr("Warning: damaged profile at %g:%d", (Int)filenamestr, (Int)line_number); if(failedparse > 4) { throw GAPException("Malformed profile");
}
}
// Now lets build a bunch of stuff which GAP will want back. // This stores the read, exec and runtime data. // vector of [filename, [ [read,exec,runtime] of line 1, [read,exec,runtime] of line 2, ... ] ]
Int len = GET_LEN_STRING(param); // Make long enough there is no chance a // resize will be needed. - 8 * 6 to allow for tabs
Obj outstring = NEW_STRING(len * 8 * 6); char* ptr = CSTR_STRING(param); char* outptr = CSTR_STRING(outstring); Int outpos = 0; for(Int i = 0; i < len; ++i)
{ switch(ptr[i]) { case'&':
outptr[outpos++] = '&';
outptr[outpos++] = 'a';
outptr[outpos++] = 'm';
outptr[outpos++] = 'p';
outptr[outpos++] = ';'; break; case'<':
outptr[outpos++] = '&';
outptr[outpos++] = 'l';
outptr[outpos++] = 't';
outptr[outpos++] = ';'; break; case' ':
outptr[outpos++] = '&';
outptr[outpos++] = 'n';
outptr[outpos++] = 'b';
outptr[outpos++] = 's';
outptr[outpos++] = 'p';
outptr[outpos++] = ';'; break; case'\t': for(int i = 0; i < 8; ++i) {
outptr[outpos++] = '&';
outptr[outpos++] = 'n';
outptr[outpos++] = 'b';
outptr[outpos++] = 's';
outptr[outpos++] = 'p';
outptr[outpos++] = ';';
} break; default:
outptr[outpos++] = ptr[i];
}
}
SET_LEN_STRING(outstring, outpos);
SHRINK_STRING(outstring); return outstring;
}
Obj FuncMD5File(Obj self, Obj filename)
{ if (!IsStringConv(filename))
{
ErrorQuit("MD5File: must be a string", 0, 0);
}
MD5Context ctx;
MD5Init(&ctx);
int fd = open(CSTR_STRING(filename), O_RDONLY); if (fd < 0)
{
ErrorQuit("MD5File: failed to open file %g", (Int)filename, 0);
}
// get the file length struct stat sb; if (fstat(fd, &sb) == -1 || sb.st_size < 0)
{
close(fd);
ErrorQuit("MD5File: failed to determine size of file %g", (Int)filename, 0);
}
off_t len = sb.st_size;
while (len > 0)
{
uint8_t buffer[4096];
size_t amount = (len < 4096 ? len : 4096);
ssize_t bytesRead = read(fd, buffer, amount); if (bytesRead < 0) {
close(fd);
ErrorQuit("MD5File: error reading from file %g", (Int)filename, 0);
}
MD5Update(&ctx, buffer, (size_t)bytesRead);
len -= bytesRead;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.