Skip to content

Compiler: move c2_trace functions to libs/c2/c2_trace.c2 #314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/compiler.c2
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,13 @@ fn void Compiler.build(Compiler* c,
if (opts.msan) c.addFeature("__MSAN__", "1");
if (opts.ubsan) c.addFeature("__UBSAN__", "1");

target.addLib(c.auxPool.add("c2", 2, true), false);

if (c.opts.trace_calls) {
if (!c.addLibFile("c2", "c2_trace.c2"))
stdlib.exit(-1);
}

c.parser = c2_parser.create(sm,
diags,
c.astPool,
Expand Down
14 changes: 14 additions & 0 deletions compiler/compiler_libs.c2
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,20 @@ fn bool Compiler.has_component(Compiler* c, u32 name) {
return false;
}

fn bool Compiler.addLibFile(Compiler* c, const char* libname, const char* filename) {
char[512] dirname;
char[512] fullname;

if (c.find_lib(libname, dirname)) {
stdio.snprintf(fullname, elemsof(fullname), "%s/%s", dirname, filename);
c.target.addFile(c.auxPool.addStr(fullname, true), 0);
return true;
} else {
console.error("c2c: find library file %s/%s", libname, filename);
return false;
}
}

fn bool Compiler.find_lib(const Compiler* c, const char* libname, char* fullpath) {
for (u32 i=0; i<c.libdirs.length(); i++) {
const char* dirname = c.libdirs.get(i);
Expand Down
2 changes: 0 additions & 2 deletions compiler/main.c2
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,6 @@ fn bool Context.build_target(Context* c,
}
}

target.addLib(c.auxPool.add("c2", 2, true), false);

compiler.build(c.auxPool, c.sm, c.diags, c.build_info, target, &c.comp_opts, &c.pluginHandler);

// TODO unload target-specific plugins?
Expand Down
18 changes: 15 additions & 3 deletions generator/c/c_generator.c2
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type Generator struct {
bool msan;
bool ubsan;
bool trace_calls;
bool no_trace; //to disable tracing on c2_trace module

// set during generation
bool cur_external; // whether current component is external
Expand Down Expand Up @@ -1054,6 +1055,9 @@ fn void Generator.on_module(void* arg, Module* m) {
gen.mod_name = m.getName();
gen.mod = m;

// Temporary disable call tracing when compiling the c2_trace module
gen.no_trace = !string.strcmp(gen.mod_name, "c2_trace");

if (gen.fast_build) {
out.clear();
gen.header.clear();
Expand Down Expand Up @@ -1251,9 +1255,17 @@ public fn void generate(string_pool.Pool* astPool,

mainComp.visitModules(Generator.on_module, &gen);

if (fast_build) gen.out.clear();
if (gen.trace_calls) gen.writeCalls(gen.out);
if (!fast_build || gen.trace_calls) {
if (fast_build) {
if (gen.trace_calls) {
gen.out.clear();
gen.out.add("#include \"c2_trace_tables.h\"\n\n");
gen.writeCalls(gen.out);
gen.write(dir, "c2_trace_tables.c", gen.out);
}
} else {
if (gen.trace_calls) {
gen.writeCalls(gen.out);
}
gen.write(dir, "build.c", gen.out);
}

Expand Down
4 changes: 2 additions & 2 deletions generator/c/c_generator_call.c2
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn void Generator.emitCall(Generator* gen, string_buffer.Buf* out, Expr* e) {
assert(func.getKind() == ExprKind.Member);
MemberExpr* m = cast<MemberExpr*>(func);
dest = m.getFullDecl();
if (gen.trace_calls) {
if (gen.trace_calls && !gen.no_trace) {
out.print("(c2_trace_counts[%d]++, ",
gen.addCall(dest.getFullName(), call.getStartLoc()));
gen.emitCNameMod(out, dest, dest.getModule());
Expand All @@ -78,7 +78,7 @@ fn void Generator.emitCall(Generator* gen, string_buffer.Buf* out, Expr* e) {
gen.emitMemberExprBase(out, func);
}
} else {
bool no_trace = false;
bool no_trace = gen.no_trace;
// can be Member or Identifier
if (func.getKind() == ExprKind.Identifier) {
IdentifierExpr* i = cast<IdentifierExpr*>(func);
Expand Down
2 changes: 1 addition & 1 deletion generator/c/c_generator_special.c2
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ fn void Generator.createMakefile(Generator* gen,
if (!m.isExternal() && m.isUsed()) out.print(" %s.o", m.getName());
}
if (gen.trace_calls) {
out.add(" build.o");
out.add(" c2_trace_tables.o");
}
out.newline();
} else {
Expand Down
181 changes: 10 additions & 171 deletions generator/c/c_generator_trace.c2
Original file line number Diff line number Diff line change
Expand Up @@ -169,196 +169,35 @@ fn void Generator.writeCalls(Generator* gen, string_buffer.Buf* out) {
if (!gen.trace_calls)
return;

out.add("static const char *c2_filenames[] = {\n");
out.add("const char *c2_filenames[] = {\n");
u32 n = gen.filenames.length();
for (u32 i = 0; i < n; i++) {
out.print(" \"%s\",\n", gen.filenames.get(i));
}
out.add("};\n\n");

out.add(
```c
struct c2_func_t {
unsigned count;
unsigned short filename_idx;
unsigned short line;
const char *funcname;
};
static struct c2_func_t c2_func_data[] = {
```);
out.add("c2_func_t c2_func_data[] = {\n");

// TODO: store function definition location
n = gen.funcnames.length();
for (u32 i = 0; i < n; i++) {
out.print(" { 0, 0, 0, \"%s\" },\n", gen.funcnames.get(i));
}
out.add(
```c
};
out.add("};\n\n");

struct c2_trace_t {
unsigned count;
unsigned char filename_idx;
unsigned char column;
unsigned short line;
unsigned short caller_idx;
unsigned short callee_idx;
};
static struct c2_trace_t c2_trace_data[] = {
```);
out.add("c2_trace_t c2_trace_data[] = {\n");
for (u32 i = 0; i < gen.calls.count; i++) {
out.print(" { 0, %d, %d, %d, %d, %d },\n",
gen.calls.array[i].filename_idx, gen.calls.array[i].column, gen.calls.array[i].line,
gen.calls.array[i].caller_idx, gen.calls.array[i].callee_idx);
}
out.add("};\n\n");

out.add(
```c
};

static const unsigned c2_trace_length = sizeof(c2_trace_data) / sizeof(c2_trace_data[0]);
unsigned c2_trace_counts[sizeof(c2_trace_data) / sizeof(c2_trace_data[0])];

char *getenv(const char *);
int dprintf(int fd, const char *format, ...);
int strcmp(const char *s1, const char *s2);
typedef unsigned long size_t;
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
int sscanf(const char *, const char *, ...);

static int c2_match_name(const char *name, const char *pattern) {
for (;;) {
char c1, c2;
while ((c1 = *name++) == (c2 = *pattern++)) {
if (!c1) return 1;
}
if (c2 == '?') {
if (c1) continue;
return 0;
}
if (c2 == '*') {
c2 = *pattern++;
if (!c2 || c2 == ',' || c2 == ';') return 1;
for (; c1; c1 = *name++) {
if (c1 == c2 && c2_match_name(name, pattern)) return 1;
}
return 0;
}
return (!c1 && (c2 == ',' || c2 == ';'));
}
}

static int c2_match_pattern(const char *name, const char *pattern) {
if (!pattern || !*pattern) return 1;
for (const char *p = pattern; *p;) {
if (c2_match_name(name, p)) return 1;
char c;
while ((c = *p++) != 0 && c != ',' && c != ';') continue;
if (c != ',') break;
}
return 0;
}

static int c2_cmp_funcs(const void *a, const void *b) {
const struct c2_trace_t *aa = a;
const struct c2_trace_t *bb = b;
struct c2_func_t *fa = &c2_func_data[aa->callee_idx];
struct c2_func_t *fb = &c2_func_data[bb->callee_idx];
if (fa->count != fb->count) return fa->count < fb->count ? 1 : -1;
if (fa != fb) return strcmp(fa->funcname, fb->funcname);
return (aa->count < bb->count) - (aa->count > bb->count);
}

static int c2_cmp_calls(const void *a, const void *b) {
const struct c2_trace_t *aa = a;
const struct c2_trace_t *bb = b;
return (aa->count < bb->count) - (aa->count > bb->count);
}

void __attribute__((destructor)) c2_trace_calls(void) {
const char *p = getenv("C2_TRACE");
const char *pattern = 0;
const char *filename = 0;
const char *caller = 0;
if (!p || !*p) return;
unsigned min = 1, min2 = 1;
int pos = 0, mode = 3, fd = 1, indent = 2;
for (; *p; p += pos) {
for (pos = 0;;) {
sscanf(p, " min%*1[=]%n%u", &pos, &min);
if (pos) break;
sscanf(p, " min2%*1[=]%n%u", &pos, &min2);
if (pos) break;
sscanf(p, " indent%*1[=]%n%u", &pos, &indent);
if (pos) break;
sscanf(p, " mode%*1[=]%n%d", &pos, &mode);
if (pos) break;
sscanf(p, " fd%*1[=]%n%d", &pos, &fd);
if (pos) break;
sscanf(p, " name%*1[=]%n", &pos);
if (pos) { pattern = p + pos; break; }
sscanf(p, " filename%*1[=]%n", &pos);
if (pos) { filename = p + pos; break; }
sscanf(p, " caller%*1[=]%n", &pos);
if (pos) { caller = p + pos; break; }
sscanf(p, "%*[^;=]%*1[=]%n", &pos);
break;
}
if (!pos) pattern = p;
while (p[pos] && p[pos++] != ';') continue;
}
if (!mode) return;
unsigned *counts = c2_trace_counts;
struct c2_trace_t* data = c2_trace_data;
unsigned n = c2_trace_length;
for (unsigned i = 0; i < n; i++) {
struct c2_trace_t *cp = &data[i];
if (c2_match_pattern(c2_func_data[cp->callee_idx].funcname, pattern)
&& c2_match_pattern(c2_filenames[cp->filename_idx], filename)
&& c2_match_pattern(c2_func_data[cp->caller_idx].funcname, caller)) {
cp->count = counts[i];
c2_func_data[cp->callee_idx].count += counts[i];
}
}
if (mode == 2) {
qsort(data, n, sizeof(*data), c2_cmp_calls);
indent = 0;
min2 = min;
} else {
qsort(data, n, sizeof(*data), c2_cmp_funcs);
}
struct c2_func_t *last = 0;
int show = 0;
for (unsigned i = 0; i < n; i++) {
struct c2_trace_t *cp = &data[i];
struct c2_func_t *func = &c2_func_data[cp->callee_idx];
unsigned count1 = func->count;
unsigned count2 = cp->count;
if (count1 < min) continue;
if (func != last) {
show = mode & 2;
if (mode & 1) {
dprintf(fd, "%.*s%s: %u call%.*s\n", show, "\n",
func->funcname, count1, count1 != 1, "s");
}
last = func;
}
if (show && count2 >= min2) {
dprintf(fd, "%*s%s:%d:%d: %s: %u call%.*s from %s\n",
indent, "",
c2_filenames[cp->filename_idx], cp->line, cp->column,
func->funcname, count2, count2 != 1, "s",
c2_func_data[cp->caller_idx].funcname);
}
}
}
```);
out.add("uint32_t c2_trace_length = sizeof(c2_trace_data) / sizeof(c2_trace_data[0]);\n"
"uint32_t c2_trace_counts[sizeof(c2_trace_data) / sizeof(c2_trace_data[0])];\n\n"
);
}

fn void Generator.writeCallExterns(Generator* gen, string_buffer.Buf* out) {
out.add(
```c
extern unsigned c2_trace_counts[];
extern void c2_trace_calls(void);
extern int atexit(void (*func)(void));
```);
out.add("extern uint32_t c2_trace_counts[];\n");
}
Loading