Skip to content

Commit ba58df2

Browse files
committed
Refactored policy profiler
Signed-off-by: Victor Moene <[email protected]>
1 parent 876ccae commit ba58df2

File tree

4 files changed

+128
-115
lines changed

4 files changed

+128
-115
lines changed

cf-agent/cf-agent.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ int main(int argc, char *argv[])
327327

328328
EvalContextProfilingStart(ctx);
329329
KeepPromises(ctx, policy, config);
330-
EvalContextProfilingEnd(ctx, policy);
330+
EvalContextProfilingEnd(ctx);
331331

332332
if (EvalAborted(ctx))
333333
{

libpromises/eval_context.c

Lines changed: 107 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,7 @@ static bool EvalContextClassPut(EvalContext *ctx, const char *ns, const char *na
127127
static const char *EvalContextCurrentNamespace(const EvalContext *ctx);
128128
static ClassRef IDRefQualify(const EvalContext *ctx, const char *id);
129129

130-
static EventFrame *EventFrameCreate(char *type, const char *name, const char *source, SourceOffset offset);
131130
static void EventFrameDestroy(EventFrame *event);
132-
static EventFrame *BundleToEventFrame(const Bundle *bp);
133-
static EventFrame *PromiseToEventFrame(const Promise *pp);
134-
static EventFrame *FunctionToEventFrame(const FnCall *fp);
135131

136132
/**
137133
* Every agent has only one EvalContext from process start to finish.
@@ -201,11 +197,8 @@ struct EvalContext_
201197

202198
/* These are needed for policy profiling */
203199
bool profiling;
204-
205-
struct {
206-
int64_t elapsed;
207-
Seq *events;
208-
} profiler;
200+
int64_t elapsed;
201+
Seq *events;
209202

210203
EvalOrder common_eval_order;
211204
EvalOrder agent_eval_order;
@@ -349,6 +342,20 @@ static StackFrame *LastStackFrameByType(const EvalContext *ctx, StackFrameType t
349342
return NULL;
350343
}
351344

345+
static StackFrame *LastStackFrameByEvent(const EvalContext *ctx)
346+
{
347+
for (size_t i = 0; i < SeqLength(ctx->stack); i++)
348+
{
349+
StackFrame *frame = LastStackFrame(ctx, i);
350+
if (frame->event != NULL)
351+
{
352+
return frame;
353+
}
354+
}
355+
356+
return NULL;
357+
}
358+
352359
static LogLevel AdjustLogLevel(LogLevel base, LogLevel adjust)
353360
{
354361
if (adjust == -1)
@@ -1110,8 +1117,8 @@ EvalContext *EvalContextNew(void)
11101117

11111118
ctx->dump_reports = false;
11121119

1113-
ctx->profiler.events = SeqNew(20, EventFrameDestroy);
1114-
ctx->profiler.elapsed = 0;
1120+
ctx->events = SeqNew(20, EventFrameDestroy);
1121+
ctx->elapsed = 0;
11151122

11161123
// evaluation order
11171124
ctx->common_eval_order = EVAL_ORDER_UNDEFINED;
@@ -1164,7 +1171,7 @@ void EvalContextDestroy(EvalContext *ctx)
11641171
ctx->remote_var_promises = NULL;
11651172
}
11661173

1167-
SeqDestroy(ctx->profiler.events);
1174+
SeqDestroy(ctx->events);
11681175
free(ctx);
11691176
}
11701177
}
@@ -1349,20 +1356,19 @@ static StackFrame *StackFrameNew(StackFrameType type, bool inherit_previous)
13491356
frame->inherits_previous = inherit_previous;
13501357
frame->path = NULL;
13511358
frame->override_immutable = false;
1352-
frame->start = EvalContextEventStart();
13531359
frame->event = NULL;
13541360

13551361
return frame;
13561362
}
13571363

1358-
static StackFrame *StackFrameNewBundle(const Bundle *owner, bool inherit_previous, bool profiling)
1364+
static StackFrame *StackFrameNewBundle(const Bundle *owner, bool inherit_previous, bool profiling, EventFrame *prev_event)
13591365
{
13601366
StackFrame *frame = StackFrameNew(STACK_FRAME_TYPE_BUNDLE, inherit_previous);
13611367

13621368
frame->data.bundle.owner = owner;
13631369
frame->data.bundle.classes = ClassTableNew();
13641370
frame->data.bundle.vars = VariableTableNew();
1365-
frame->event = (profiling) ? BundleToEventFrame(owner) : NULL;
1371+
frame->event = (profiling) ? BundleToEventFrame(owner, prev_event) : NULL;
13661372

13671373
return frame;
13681374
}
@@ -1386,12 +1392,12 @@ static StackFrame *StackFrameNewBundleSection(const BundleSection *owner)
13861392
return frame;
13871393
}
13881394

1389-
static StackFrame *StackFrameNewPromise(const Promise *owner, bool profiling)
1395+
static StackFrame *StackFrameNewPromise(const Promise *owner, bool profiling, EventFrame *prev_event)
13901396
{
13911397
StackFrame *frame = StackFrameNew(STACK_FRAME_TYPE_PROMISE, true);
13921398

13931399
frame->data.promise.owner = owner;
1394-
frame->event = (profiling) ? PromiseToEventFrame(owner) : NULL;
1400+
frame->event = (profiling) ? PromiseToEventFrame(owner, prev_event) : NULL;
13951401

13961402
return frame;
13971403
}
@@ -1443,7 +1449,8 @@ void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, cons
14431449
assert(ctx != NULL);
14441450
assert(!LastStackFrame(ctx, 0) || LastStackFrame(ctx, 0)->type == STACK_FRAME_TYPE_PROMISE_ITERATION);
14451451

1446-
EvalContextStackPushFrame(ctx, StackFrameNewBundle(owner, inherits_previous, ctx->profiling));
1452+
StackFrame *frame = StackFrameNewBundle(owner, inherits_previous, ctx->profiling, EvalContextGetLastEventFrame(ctx));
1453+
EvalContextStackPushFrame(ctx, frame);
14471454

14481455
if (RlistLen(args) > 0)
14491456
{
@@ -1523,8 +1530,7 @@ void EvalContextStackPushPromiseFrame(EvalContext *ctx, const Promise *owner)
15231530

15241531
EvalContextVariableClearMatch(ctx);
15251532

1526-
StackFrame *frame = StackFrameNewPromise(owner, ctx->profiling);
1527-
1533+
StackFrame *frame = StackFrameNewPromise(owner, ctx->profiling, EvalContextGetLastEventFrame(ctx));
15281534
EvalContextStackPushFrame(ctx, frame);
15291535

15301536
// create an empty table
@@ -1615,15 +1621,11 @@ void EvalContextStackPopFrame(EvalContext *ctx)
16151621

16161622
StackFrame *last_frame = LastStackFrame(ctx, 0);
16171623
StackFrameType last_frame_type = last_frame->type;
1618-
int64_t start = last_frame->start;
1619-
int64_t end = EvalContextEventStart();
16201624

16211625
EventFrame *last_event = last_frame->event;
16221626
if (last_event != NULL)
16231627
{
1624-
assert(end >= start); /* sanity check */
1625-
last_event->elapsed = end - start;
1626-
SeqAppend(ctx->profiler.events, last_event);
1628+
EvalContextAppendEventFrame(ctx, last_event);
16271629
}
16281630

16291631
switch (last_frame_type)
@@ -3892,22 +3894,40 @@ bool EvalContextOverrideImmutableGet(EvalContext *ctx)
38923894

38933895
// ##############################################################
38943896

3895-
void EvalContextSetProfiling(EvalContext *ctx, bool profiling)
3897+
static int64_t EvalContextEventStart()
38963898
{
3897-
assert(ctx != NULL);
3898-
ctx->profiling = profiling;
3899+
struct timespec ts;
3900+
#ifdef CLOCK_MONOTONIC
3901+
clock_gettime(CLOCK_MONOTONIC, &ts);
3902+
#else
3903+
// As in libcfnet/net.c some OS-es don't have monotonic clock, realtime clock is best we can do.
3904+
clock_gettime(CLOCK_REALTIME, &ts);
3905+
#endif
3906+
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
38993907
}
39003908

3901-
static EventFrame *EventFrameCreate(char *type, const char *name, const char *source, SourceOffset offset)
3909+
static EventFrame *EventFrameCreate(const char *source,
3910+
char *component,
3911+
char *type,
3912+
const char *ns,
3913+
const char *name,
3914+
SourceOffset offset,
3915+
EventFrame *prev,
3916+
char *id
3917+
)
39023918
{
39033919
EventFrame *event = (EventFrame *) xmalloc(sizeof(EventFrame));
3920+
event->elapsed = EvalContextEventStart();
39043921

3922+
event->source = GetAbsolutePath(source);
3923+
event->component = component;
39053924
event->type = type;
3925+
event->ns = SafeStringDuplicate(ns);
39063926
event->name = SafeStringDuplicate(name);
3907-
event->filename = GetAbsolutePath(source);
3908-
event->elapsed = 0;
39093927
event->offset = offset;
3910-
event->id = StringFormat("%s_%s_%s_%ld_%ld", type, name, source, offset.start, offset.line);
3928+
3929+
event->id = id;
3930+
event->callstack = (prev != NULL) ? StringFormat("%s;%s", prev->callstack, event->id) : SafeStringDuplicate(event->id);
39113931

39123932
return event;
39133933
}
@@ -3916,9 +3936,12 @@ static void EventFrameDestroy(EventFrame *event)
39163936
{
39173937
if (event != NULL)
39183938
{
3919-
free(event->filename);
3920-
free(event->id);
3939+
free(event->source);
3940+
free(event->ns);
39213941
free(event->name);
3942+
3943+
free(event->id);
3944+
free(event->callstack);
39223945
free(event);
39233946
}
39243947
}
@@ -3928,11 +3951,14 @@ static JsonElement *EventToJson(EventFrame *event)
39283951
assert(event != NULL);
39293952
JsonElement *json_event = JsonObjectCreate(10);
39303953

3954+
JsonObjectAppendString(json_event, "component", event->component);
39313955
JsonObjectAppendString(json_event, "type", event->type);
39323956
JsonObjectAppendString(json_event, "name", event->name);
3933-
JsonObjectAppendString(json_event, "filename", event->filename);
3957+
JsonObjectAppendString(json_event, "namespace", event->ns);
3958+
JsonObjectAppendString(json_event, "source", event->source);
39343959
JsonObjectAppendString(json_event, "id", event->id);
39353960
JsonObjectAppendInteger64(json_event, "elapsed", event->elapsed);
3961+
JsonObjectAppendString(json_event, "callstack", event->callstack);
39363962

39373963
JsonElement *offset = JsonObjectCreate(4);
39383964
JsonObjectAppendInteger(offset, "start", event->offset.start);
@@ -3945,81 +3971,46 @@ static JsonElement *EventToJson(EventFrame *event)
39453971
return json_event;
39463972
}
39473973

3948-
static EventFrame *BundleToEventFrame(const Bundle *bp)
3974+
EventFrame *BundleToEventFrame(const Bundle *bp, EventFrame *prev_frame)
39493975
{
39503976
assert(bp != NULL);
3951-
return EventFrameCreate("bundle", bp->name, bp->source_path, bp->offset);
3977+
char *id = StringFormat("%s:%ld/%s_%s_%s:%s", GetAbsolutePath(bp->source_path), bp->offset.line, "bundle", bp->type, bp->ns, bp->name);
3978+
return EventFrameCreate(bp->source_path, "bundle", bp->type, bp->ns, bp->name, bp->offset, prev_frame, id);
39523979
}
39533980

3954-
static EventFrame *PromiseToEventFrame(const Promise *pp)
3981+
EventFrame *PromiseToEventFrame(const Promise *pp, EventFrame *prev_frame)
39553982
{
39563983
assert(pp != NULL);
3957-
return EventFrameCreate("promise", PromiseGetPromiseType(pp), PromiseGetBundle(pp)->source_path, pp->offset);
3984+
char *id = StringFormat("%s:%ld/%s_%s", PromiseGetBundle(pp)->source_path, pp->offset.line, "promise", pp->parent_section->promise_type);
3985+
return EventFrameCreate(PromiseGetBundle(pp)->source_path, "promise", pp->parent_section->promise_type, "x", "x", pp->offset, prev_frame, id);
39583986
}
39593987

3960-
static EventFrame *FunctionToEventFrame(const FnCall *fp)
3988+
EventFrame *FunctionToEventFrame(const FnCall *fp, EventFrame *prev_frame)
39613989
{
39623990
assert(fp != NULL);
3963-
return EventFrameCreate("function", fp->name, PromiseGetBundle(fp->caller)->source_path, fp->caller->offset);
3991+
char *id = StringFormat("%s:%ld/%s_%s", PromiseGetBundle(fp->caller)->source_path, fp->caller->offset.line, "function", fp->name);
3992+
return EventFrameCreate(PromiseGetBundle(fp->caller)->source_path, "function", "x", "x", fp->name, fp->caller->offset, prev_frame, id);
39643993
}
39653994

3966-
void EvalContextAddFunctionEvent(EvalContext *ctx, const FnCall *fp, int64_t start)
3995+
void EvalContextSetProfiling(EvalContext *ctx, bool profiling)
39673996
{
39683997
assert(ctx != NULL);
3969-
if (ctx->profiling)
3970-
{
3971-
EventFrame *event = FunctionToEventFrame(fp);
3972-
int64_t end = EvalContextEventStart();
3973-
assert(end >= start); /* sanity check */
3974-
event->elapsed = end - start;
3975-
SeqAppend(ctx->profiler.events, event);
3976-
}
3998+
ctx->profiling = profiling;
39773999
}
39784000

3979-
int64_t EvalContextEventStart()
4001+
bool EvalContextGetProfiling(EvalContext *ctx)
39804002
{
3981-
struct timespec ts;
3982-
#ifdef CLOCK_MONOTONIC
3983-
clock_gettime(CLOCK_MONOTONIC, &ts);
3984-
#else
3985-
// As in libcfnet/net.c some OS-es don't have monotonic clock, realtime clock is best we can do.
3986-
clock_gettime(CLOCK_REALTIME, &ts);
3987-
#endif
3988-
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
4003+
assert(ctx != NULL);
4004+
return ctx->profiling;
39894005
}
39904006

39914007
void EvalContextProfilingStart(EvalContext *ctx)
39924008
{
39934009
assert(ctx != NULL);
3994-
ctx->profiler.elapsed = EvalContextEventStart();
4010+
ctx->elapsed = EvalContextEventStart();
39954011
}
39964012

3997-
static HashMap *SumEventFrames(Seq *events)
3998-
{
3999-
HashMap *map = HashMapNew((MapHashFn) StringHash, (MapKeyEqualFn) StringEqual, NULL, NULL, 10);
4000-
4001-
size_t length = SeqLength(events);
4002-
EventFrame *curr;
4003-
EventFrame *prev;
4004-
MapKeyValue *mkv;
4005-
for (int i = 0; i < length; i++)
4006-
{
4007-
curr = SeqAt(events, i);
4008-
mkv = HashMapGet(map, curr->id);
4009-
4010-
if (mkv == NULL)
4011-
{
4012-
HashMapInsert(map, curr->id, curr);
4013-
continue;
4014-
}
4015-
prev = mkv->value;
4016-
prev->elapsed += curr->elapsed;
4017-
}
4018-
4019-
return map;
4020-
}
4021-
4022-
void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
4013+
void EvalContextProfilingEnd(EvalContext *ctx)
40234014
{
40244015
assert(ctx != NULL);
40254016

@@ -4029,35 +4020,48 @@ void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
40294020
}
40304021

40314022
int64_t end = EvalContextEventStart();
4032-
int64_t start = ctx->profiler.elapsed;
4023+
int64_t start = ctx->elapsed;
40334024
assert(end >= start); /* sanity check */
40344025

4035-
ctx->profiler.elapsed = end - start;
4036-
4037-
HashMap *map = SumEventFrames(ctx->profiler.events);
4038-
JsonElement *profiling = JsonObjectCreate(2);
4039-
4040-
JsonElement *json_policy = PolicyToJson(policy);
4041-
JsonObjectAppendObject(profiling, "policy", json_policy);
4026+
ctx->elapsed = end - start;
40424027

40434028
JsonElement *events = JsonArrayCreate(10);
40444029
{
4045-
HashMapIterator iter = HashMapIteratorInit(map);
4046-
MapKeyValue *mkv;
4047-
while ((mkv = HashMapIteratorNext(&iter)) != NULL)
4030+
for (size_t i = 0; i < SeqLength(ctx->events); i++)
40484031
{
4049-
EventFrame *event = mkv->value;
4032+
EventFrame *event = SeqAt(ctx->events, i);
40504033
JsonArrayAppendObject(events, EventToJson(event));
40514034
}
40524035
}
4053-
JsonObjectAppendArray(profiling, "events", events);
4054-
40554036
// write
40564037
Writer *writer = FileWriter(stdout);
4057-
JsonWrite(writer, profiling, 2);
4038+
JsonWrite(writer, events, 2);
40584039
WriterClose(writer);
40594040

4060-
JsonDestroy(profiling);
4041+
JsonDestroy(events);
4042+
}
4043+
4044+
EventFrame *EvalContextGetLastEventFrame(EvalContext *ctx)
4045+
{
4046+
StackFrame *frame = LastStackFrameByEvent(ctx);
4047+
4048+
if (frame == NULL)
4049+
{
4050+
return NULL;
4051+
}
4052+
4053+
return frame->event;
4054+
}
4055+
4056+
void EvalContextAppendEventFrame(EvalContext *ctx, EventFrame *event)
4057+
{
4058+
int64_t start = event->elapsed;
4059+
int64_t end = EvalContextEventStart();
4060+
assert(end >= start); /* sanity check */
4061+
4062+
event->elapsed = end - start;
4063+
4064+
SeqAppend(ctx->events, event);
40614065
}
40624066

40634067
// ##############################################################
@@ -4127,4 +4131,4 @@ bool EvalContextIsClassicOrder(EvalContext *ctx, const Bundle *bp)
41274131
// The fallback is to use what is defined in body common control,
41284132
// or if not defined there either, default to true (normal order)
41294133
return (ctx->common_eval_order != EVAL_ORDER_TOP_DOWN);
4130-
}
4134+
}

0 commit comments

Comments
 (0)