Skip to content

Commit c0e36cd

Browse files
committed
Refactored policy profiler
Signed-off-by: Victor Moene <victor.moene@northern.tech>
1 parent fc969e3 commit c0e36cd

File tree

4 files changed

+120
-115
lines changed

4 files changed

+120
-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: 99 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,21 @@ static StackFrame *LastStackFrameByType(const EvalContext *ctx, StackFrameType t
349342
return NULL;
350343
}
351344

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

11111119
ctx->dump_reports = false;
11121120

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

11161124
// evaluation order
11171125
ctx->common_eval_order = EVAL_ORDER_UNDEFINED;
@@ -1164,7 +1172,7 @@ void EvalContextDestroy(EvalContext *ctx)
11641172
ctx->remote_var_promises = NULL;
11651173
}
11661174

1167-
SeqDestroy(ctx->profiler.events);
1175+
SeqDestroy(ctx->events);
11681176
free(ctx);
11691177
}
11701178
}
@@ -1349,20 +1357,19 @@ static StackFrame *StackFrameNew(StackFrameType type, bool inherit_previous)
13491357
frame->inherits_previous = inherit_previous;
13501358
frame->path = NULL;
13511359
frame->override_immutable = false;
1352-
frame->start = EvalContextEventStart();
13531360
frame->event = NULL;
13541361

13551362
return frame;
13561363
}
13571364

1358-
static StackFrame *StackFrameNewBundle(const Bundle *owner, bool inherit_previous, bool profiling)
1365+
static StackFrame *StackFrameNewBundle(const Bundle *owner, bool inherit_previous, bool profiling, EventFrame *prev_event)
13591366
{
13601367
StackFrame *frame = StackFrameNew(STACK_FRAME_TYPE_BUNDLE, inherit_previous);
13611368

13621369
frame->data.bundle.owner = owner;
13631370
frame->data.bundle.classes = ClassTableNew();
13641371
frame->data.bundle.vars = VariableTableNew();
1365-
frame->event = (profiling) ? BundleToEventFrame(owner) : NULL;
1372+
frame->event = (profiling) ? BundleToEventFrame(owner, prev_event) : NULL;
13661373

13671374
return frame;
13681375
}
@@ -1386,12 +1393,12 @@ static StackFrame *StackFrameNewBundleSection(const BundleSection *owner)
13861393
return frame;
13871394
}
13881395

1389-
static StackFrame *StackFrameNewPromise(const Promise *owner, bool profiling)
1396+
static StackFrame *StackFrameNewPromise(const Promise *owner, bool profiling, EventFrame *prev_event)
13901397
{
13911398
StackFrame *frame = StackFrameNew(STACK_FRAME_TYPE_PROMISE, true);
13921399

13931400
frame->data.promise.owner = owner;
1394-
frame->event = (profiling) ? PromiseToEventFrame(owner) : NULL;
1401+
frame->event = (profiling) ? PromiseToEventFrame(owner, prev_event) : NULL;
13951402

13961403
return frame;
13971404
}
@@ -1443,7 +1450,8 @@ void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, cons
14431450
assert(ctx != NULL);
14441451
assert(!LastStackFrame(ctx, 0) || LastStackFrame(ctx, 0)->type == STACK_FRAME_TYPE_PROMISE_ITERATION);
14451452

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

14481456
if (RlistLen(args) > 0)
14491457
{
@@ -1523,8 +1531,7 @@ void EvalContextStackPushPromiseFrame(EvalContext *ctx, const Promise *owner)
15231531

15241532
EvalContextVariableClearMatch(ctx);
15251533

1526-
StackFrame *frame = StackFrameNewPromise(owner, ctx->profiling);
1527-
1534+
StackFrame *frame = StackFrameNewPromise(owner, ctx->profiling, EvalContextGetLastEventFrame(ctx));
15281535
EvalContextStackPushFrame(ctx, frame);
15291536

15301537
// create an empty table
@@ -1615,15 +1622,11 @@ void EvalContextStackPopFrame(EvalContext *ctx)
16151622

16161623
StackFrame *last_frame = LastStackFrame(ctx, 0);
16171624
StackFrameType last_frame_type = last_frame->type;
1618-
int64_t start = last_frame->start;
1619-
int64_t end = EvalContextEventStart();
16201625

16211626
EventFrame *last_event = last_frame->event;
16221627
if (last_event != NULL)
16231628
{
1624-
assert(end >= start); /* sanity check */
1625-
last_event->elapsed = end - start;
1626-
SeqAppend(ctx->profiler.events, last_event);
1629+
EvalContextAppendEventFrame(ctx, last_event);
16271630
}
16281631

16291632
switch (last_frame_type)
@@ -3892,22 +3895,33 @@ bool EvalContextOverrideImmutableGet(EvalContext *ctx)
38923895

38933896
// ##############################################################
38943897

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

3901-
static EventFrame *EventFrameCreate(char *type, const char *name, const char *source, SourceOffset offset)
3910+
static EventFrame *EventFrameCreate(const char *source, char *component, char *type, const char *ns, const char *name,
3911+
SourceOffset offset, EventFrame *prev, char *id)
39023912
{
39033913
EventFrame *event = (EventFrame *) xmalloc(sizeof(EventFrame));
3914+
event->elapsed = EvalContextEventStart();
39043915

3916+
event->source = GetAbsolutePath(source);
3917+
event->component = component;
39053918
event->type = type;
3919+
event->ns = SafeStringDuplicate(ns);
39063920
event->name = SafeStringDuplicate(name);
3907-
event->filename = GetAbsolutePath(source);
3908-
event->elapsed = 0;
39093921
event->offset = offset;
3910-
event->id = StringFormat("%s_%s_%s_%ld_%ld", type, name, source, offset.start, offset.line);
3922+
3923+
event->id = id;
3924+
event->callstack = (prev != NULL) ? StringFormat("%s;%s", prev->callstack, event->id) : SafeStringDuplicate(event->id);
39113925

39123926
return event;
39133927
}
@@ -3916,9 +3930,12 @@ static void EventFrameDestroy(EventFrame *event)
39163930
{
39173931
if (event != NULL)
39183932
{
3919-
free(event->filename);
3920-
free(event->id);
3933+
free(event->source);
3934+
free(event->ns);
39213935
free(event->name);
3936+
3937+
free(event->id);
3938+
free(event->callstack);
39223939
free(event);
39233940
}
39243941
}
@@ -3928,11 +3945,14 @@ static JsonElement *EventToJson(EventFrame *event)
39283945
assert(event != NULL);
39293946
JsonElement *json_event = JsonObjectCreate(10);
39303947

3948+
JsonObjectAppendString(json_event, "component", event->component);
39313949
JsonObjectAppendString(json_event, "type", event->type);
39323950
JsonObjectAppendString(json_event, "name", event->name);
3933-
JsonObjectAppendString(json_event, "filename", event->filename);
3951+
JsonObjectAppendString(json_event, "namespace", event->ns);
3952+
JsonObjectAppendString(json_event, "source", event->source);
39343953
JsonObjectAppendString(json_event, "id", event->id);
39353954
JsonObjectAppendInteger64(json_event, "elapsed", event->elapsed);
3955+
JsonObjectAppendString(json_event, "callstack", event->callstack);
39363956

39373957
JsonElement *offset = JsonObjectCreate(4);
39383958
JsonObjectAppendInteger(offset, "start", event->offset.start);
@@ -3945,81 +3965,46 @@ static JsonElement *EventToJson(EventFrame *event)
39453965
return json_event;
39463966
}
39473967

3948-
static EventFrame *BundleToEventFrame(const Bundle *bp)
3968+
EventFrame *BundleToEventFrame(const Bundle *bp, EventFrame *prev_frame)
39493969
{
39503970
assert(bp != NULL);
3951-
return EventFrameCreate("bundle", bp->name, bp->source_path, bp->offset);
3971+
char *id = StringFormat("%s:%ld/%s_%s_%s:%s", GetAbsolutePath(bp->source_path), bp->offset.line, "bundle", bp->type, bp->ns, bp->name);
3972+
return EventFrameCreate(bp->source_path, "bundle", bp->type, bp->ns, bp->name, bp->offset, prev_frame, id);
39523973
}
39533974

3954-
static EventFrame *PromiseToEventFrame(const Promise *pp)
3975+
EventFrame *PromiseToEventFrame(const Promise *pp, EventFrame *prev_frame)
39553976
{
39563977
assert(pp != NULL);
3957-
return EventFrameCreate("promise", PromiseGetPromiseType(pp), PromiseGetBundle(pp)->source_path, pp->offset);
3978+
char *id = StringFormat("%s:%ld/%s_%s", PromiseGetBundle(pp)->source_path, pp->offset.line, "promise", pp->parent_section->promise_type);
3979+
return EventFrameCreate(PromiseGetBundle(pp)->source_path, "promise", pp->parent_section->promise_type, "x", "x", pp->offset, prev_frame, id);
39583980
}
39593981

3960-
static EventFrame *FunctionToEventFrame(const FnCall *fp)
3982+
EventFrame *FunctionToEventFrame(const FnCall *fp, EventFrame *prev_frame)
39613983
{
39623984
assert(fp != NULL);
3963-
return EventFrameCreate("function", fp->name, PromiseGetBundle(fp->caller)->source_path, fp->caller->offset);
3985+
char *id = StringFormat("%s:%ld/%s_%s", PromiseGetBundle(fp->caller)->source_path, fp->caller->offset.line, "function", fp->name);
3986+
return EventFrameCreate(PromiseGetBundle(fp->caller)->source_path, "function", "x", "x", fp->name, fp->caller->offset, prev_frame, id);
39643987
}
39653988

3966-
void EvalContextAddFunctionEvent(EvalContext *ctx, const FnCall *fp, int64_t start)
3989+
void EvalContextSetProfiling(EvalContext *ctx, bool profiling)
39673990
{
39683991
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-
}
3992+
ctx->profiling = profiling;
39773993
}
39783994

3979-
int64_t EvalContextEventStart()
3995+
bool EvalContextGetProfiling(EvalContext *ctx)
39803996
{
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;
3997+
assert(ctx != NULL);
3998+
return ctx->profiling;
39893999
}
39904000

39914001
void EvalContextProfilingStart(EvalContext *ctx)
39924002
{
39934003
assert(ctx != NULL);
3994-
ctx->profiler.elapsed = EvalContextEventStart();
3995-
}
3996-
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;
4004+
ctx->elapsed = EvalContextEventStart();
40204005
}
40214006

4022-
void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
4007+
void EvalContextProfilingEnd(EvalContext *ctx)
40234008
{
40244009
assert(ctx != NULL);
40254010

@@ -4029,35 +4014,46 @@ void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
40294014
}
40304015

40314016
int64_t end = EvalContextEventStart();
4032-
int64_t start = ctx->profiler.elapsed;
4017+
int64_t start = ctx->elapsed;
40334018
assert(end >= start); /* sanity check */
40344019

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);
4020+
ctx->elapsed = end - start;
40424021

40434022
JsonElement *events = JsonArrayCreate(10);
40444023
{
4045-
HashMapIterator iter = HashMapIteratorInit(map);
4046-
MapKeyValue *mkv;
4047-
while ((mkv = HashMapIteratorNext(&iter)) != NULL)
4024+
for (size_t i = 0; i < SeqLength(ctx->events); i++)
40484025
{
4049-
EventFrame *event = mkv->value;
4026+
EventFrame *event = SeqAt(ctx->events, i);
40504027
JsonArrayAppendObject(events, EventToJson(event));
40514028
}
40524029
}
4053-
JsonObjectAppendArray(profiling, "events", events);
4054-
40554030
// write
40564031
Writer *writer = FileWriter(stdout);
4057-
JsonWrite(writer, profiling, 2);
4032+
JsonWrite(writer, events, 2);
40584033
WriterClose(writer);
40594034

4060-
JsonDestroy(profiling);
4035+
JsonDestroy(events);
4036+
}
4037+
4038+
EventFrame *EvalContextGetLastEventFrame(EvalContext *ctx)
4039+
{
4040+
StackFrame *frame = LastStackFrameByEvent(ctx);
4041+
4042+
return (frame == NULL) ? NULL : frame->event;
4043+
}
4044+
4045+
void EvalContextAppendEventFrame(EvalContext *ctx, EventFrame *event)
4046+
{
4047+
assert(ctx != NULL);
4048+
assert(event != NULL);
4049+
4050+
int64_t start = event->elapsed;
4051+
int64_t end = EvalContextEventStart();
4052+
assert(end >= start); /* sanity check */
4053+
4054+
event->elapsed = end - start;
4055+
4056+
SeqAppend(ctx->events, event);
40614057
}
40624058

40634059
// ##############################################################
@@ -4127,4 +4123,4 @@ bool EvalContextIsClassicOrder(EvalContext *ctx, const Bundle *bp)
41274123
// The fallback is to use what is defined in body common control,
41284124
// or if not defined there either, default to true (normal order)
41294125
return (ctx->common_eval_order != EVAL_ORDER_TOP_DOWN);
4130-
}
4126+
}

0 commit comments

Comments
 (0)