Skip to content

Commit

Permalink
Add Info, Warning and Error severity kinds to alerts
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Jun 12, 2023
1 parent 5f60c68 commit 32e812c
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 273 deletions.
270 changes: 26 additions & 244 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2040,210 +2040,6 @@ void flecs_resume_readonly(

#endif

/**
* @file datastructures/qsort.h
* @brief Quicksort implementation.
*/

/* From: https://github.com/svpv/qsort/blob/master/qsort.h
* Use custom qsort implementation rather than relying on the version in libc to
* ensure that results are consistent across platforms.
*/

/*
* Copyright (c) 2013, 2017 Alexey Tourbin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

/*
* This is a traditional Quicksort implementation which mostly follows
* [Sedgewick 1978]. Sorting is performed entirely on array indices,
* while actual access to the array elements is abstracted out with the
* user-defined `LESS` and `SWAP` primitives.
*
* Synopsis:
* QSORT(N, LESS, SWAP);
* where
* N - the number of elements in A[];
* LESS(i, j) - compares A[i] to A[j];
* SWAP(i, j) - exchanges A[i] with A[j].
*/

#ifndef QSORT_H
#define QSORT_H

/* Sort 3 elements. */
#define Q_SORT3(q_a1, q_a2, q_a3, Q_LESS, Q_SWAP) \
do { \
if (Q_LESS(q_a2, q_a1)) { \
if (Q_LESS(q_a3, q_a2)) \
Q_SWAP(q_a1, q_a3); \
else { \
Q_SWAP(q_a1, q_a2); \
if (Q_LESS(q_a3, q_a2)) \
Q_SWAP(q_a2, q_a3); \
} \
} \
else if (Q_LESS(q_a3, q_a2)) { \
Q_SWAP(q_a2, q_a3); \
if (Q_LESS(q_a2, q_a1)) \
Q_SWAP(q_a1, q_a2); \
} \
} while (0)

/* Partition [q_l,q_r] around a pivot. After partitioning,
* [q_l,q_j] are the elements that are less than or equal to the pivot,
* while [q_i,q_r] are the elements greater than or equal to the pivot. */
#define Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP) \
do { \
/* The middle element, not to be confused with the median. */ \
Q_UINT q_m = q_l + ((q_r - q_l) >> 1); \
/* Reorder the second, the middle, and the last items. \
* As [Edelkamp Weiss 2016] explain, using the second element \
* instead of the first one helps avoid bad behaviour for \
* decreasingly sorted arrays. This method is used in recent \
* versions of gcc's std::sort, see gcc bug 58437#c13, although \
* the details are somewhat different (cf. #c14). */ \
Q_SORT3(q_l + 1, q_m, q_r, Q_LESS, Q_SWAP); \
/* Place the median at the beginning. */ \
Q_SWAP(q_l, q_m); \
/* Partition [q_l+2, q_r-1] around the median which is in q_l. \
* q_i and q_j are initially off by one, they get decremented \
* in the do-while loops. */ \
q_i = q_l + 1; q_j = q_r; \
while (1) { \
do q_i++; while (Q_LESS(q_i, q_l)); \
do q_j--; while (Q_LESS(q_l, q_j)); \
if (q_i >= q_j) break; /* Sedgewick says "until j < i" */ \
Q_SWAP(q_i, q_j); \
} \
/* Compensate for the i==j case. */ \
q_i = q_j + 1; \
/* Put the median to its final place. */ \
Q_SWAP(q_l, q_j); \
/* The median is not part of the left subfile. */ \
q_j--; \
} while (0)

/* Insertion sort is applied to small subfiles - this is contrary to
* Sedgewick's suggestion to run a separate insertion sort pass after
* the partitioning is done. The reason I don't like a separate pass
* is that it triggers extra comparisons, because it can't see that the
* medians are already in their final positions and need not be rechecked.
* Since I do not assume that comparisons are cheap, I also do not try
* to eliminate the (q_j > q_l) boundary check. */
#define Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP) \
do { \
Q_UINT q_i, q_j; \
/* For each item starting with the second... */ \
for (q_i = q_l + 1; q_i <= q_r; q_i++) \
/* move it down the array so that the first part is sorted. */ \
for (q_j = q_i; q_j > q_l && (Q_LESS(q_j, q_j - 1)); q_j--) \
Q_SWAP(q_j, q_j - 1); \
} while (0)

/* When the size of [q_l,q_r], i.e. q_r-q_l+1, is greater than or equal to
* Q_THRESH, the algorithm performs recursive partitioning. When the size
* drops below Q_THRESH, the algorithm switches to insertion sort.
* The minimum valid value is probably 5 (with 5 items, the second and
* the middle items, the middle itself being rounded down, are distinct). */
#define Q_THRESH 16

/* The main loop. */
#define Q_LOOP(Q_UINT, Q_N, Q_LESS, Q_SWAP) \
do { \
Q_UINT q_l = 0; \
Q_UINT q_r = (Q_N) - 1; \
Q_UINT q_sp = 0; /* the number of frames pushed to the stack */ \
struct { Q_UINT q_l, q_r; } \
/* On 32-bit platforms, to sort a "char[3GB+]" array, \
* it may take full 32 stack frames. On 64-bit CPUs, \
* though, the address space is limited to 48 bits. \
* The usage is further reduced if Q_N has a 32-bit type. */ \
q_st[sizeof(Q_UINT) > 4 && sizeof(Q_N) > 4 ? 48 : 32]; \
while (1) { \
if (q_r - q_l + 1 >= Q_THRESH) { \
Q_UINT q_i, q_j; \
Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP); \
/* Now have two subfiles: [q_l,q_j] and [q_i,q_r]. \
* Dealing with them depends on which one is bigger. */ \
if (q_j - q_l >= q_r - q_i) \
Q_SUBFILES(q_l, q_j, q_i, q_r); \
else \
Q_SUBFILES(q_i, q_r, q_l, q_j); \
} \
else { \
Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP); \
/* Pop subfiles from the stack, until it gets empty. */ \
if (q_sp == 0) break; \
q_sp--; \
q_l = q_st[q_sp].q_l; \
q_r = q_st[q_sp].q_r; \
} \
} \
} while (0)

/* The missing part: dealing with subfiles.
* Assumes that the first subfile is not smaller than the second. */
#define Q_SUBFILES(q_l1, q_r1, q_l2, q_r2) \
do { \
/* If the second subfile is only a single element, it needs \
* no further processing. The first subfile will be processed \
* on the next iteration (both subfiles cannot be only a single \
* element, due to Q_THRESH). */ \
if (q_l2 == q_r2) { \
q_l = q_l1; \
q_r = q_r1; \
} \
else { \
/* Otherwise, both subfiles need processing. \
* Push the larger subfile onto the stack. */ \
q_st[q_sp].q_l = q_l1; \
q_st[q_sp].q_r = q_r1; \
q_sp++; \
/* Process the smaller subfile on the next iteration. */ \
q_l = q_l2; \
q_r = q_r2; \
} \
} while (0)

/* And now, ladies and gentlemen, may I proudly present to you... */
#define QSORT(Q_N, Q_LESS, Q_SWAP) \
do { \
if ((Q_N) > 1) \
/* We could check sizeof(Q_N) and use "unsigned", but at least \
* on x86_64, this has the performance penalty of up to 5%. */ \
Q_LOOP(ecs_size_t, Q_N, Q_LESS, Q_SWAP); \
} while (0)

void ecs_qsort(
void *base,
ecs_size_t nitems,
ecs_size_t size,
int (*compar)(const void *, const void*));

#define ecs_qsort_t(base, nitems, T, compar) \
ecs_qsort(base, nitems, ECS_SIZEOF(T), compar)

#endif

/**
* @file datastructures/name_index.h
* @brief Data structure for resolving 64bit keys by string (name).
Expand Down Expand Up @@ -2573,11 +2369,6 @@ int flecs_entity_compare(
ecs_entity_t e2,
const void *ptr2);

/* Compare function for entity ids which can be used with qsort */
int flecs_entity_compare_qsort(
const void *e1,
const void *e2);

bool flecs_name_is_id(
const char *name);

Expand Down Expand Up @@ -13385,31 +13176,6 @@ uint64_t flecs_hash(
return wyhash(data, flecs_ito(size_t, length), 0, _wyp);
}

/**
* @file datastructures/qsort.c
* @brief Quicksort implementation.
*/


void ecs_qsort(
void *base,
ecs_size_t nitems,
ecs_size_t size,
int (*compar)(const void *, const void*))
{
void *tmp = ecs_os_alloca(size); /* For swap */

#define LESS(i, j) \
compar(ECS_ELEM(base, size, i), ECS_ELEM(base, size, j)) < 0

#define SWAP(i, j) \
ecs_os_memcpy(tmp, ECS_ELEM(base, size, i), size),\
ecs_os_memcpy(ECS_ELEM(base, size, i), ECS_ELEM(base, size, j), size),\
ecs_os_memcpy(ECS_ELEM(base, size, j), tmp, size)

QSORT(nitems, LESS, SWAP);
}

/**
* @file datastructures/bitset.c
* @brief Bitset data structure.
Expand Down Expand Up @@ -19680,7 +19446,7 @@ void MonitorAlerts(ecs_iter_t *it) {
ecs_set(world, ai, EcsAlertInstance, { .message = NULL });
ecs_set(world, ai, EcsMetricSource, { .entity = e });
ecs_set(world, ai, EcsMetricValue, { .value = 0 });
ecs_doc_set_color(world, ai, "#b5494b");
// ecs_doc_set_color(world, ai, "#b5494b");
ecs_defer_suspend(it->world);
flecs_alerts_add_alert_to_src(world, e, a, ai);
ecs_defer_resume(it->world);
Expand Down Expand Up @@ -19806,6 +19572,14 @@ ecs_entity_t ecs_alert_init(
ecs_add(world, result, EcsMetric);
ecs_add_pair(world, result, EcsMetric, EcsCounter);

/* Add severity to alert */
ecs_entity_t severity = desc->severity;
if (!severity) {
severity = EcsAlertError;
}

ecs_add_pair(world, result, ecs_id(EcsAlert), severity);

if (desc->brief) {
#ifdef FLECS_DOC
ecs_doc_set_brief(world, result, desc->brief);
Expand Down Expand Up @@ -19879,11 +19653,17 @@ void FlecsAlertsImport(ecs_world_t *world) {

ecs_set_name_prefix(world, "Ecs");
ECS_COMPONENT_DEFINE(world, EcsAlert);
ecs_remove_pair(world, ecs_id(EcsAlert), ecs_id(EcsIdentifier), EcsSymbol);

ecs_set_name_prefix(world, "EcsAlert");
ECS_COMPONENT_DEFINE(world, EcsAlertInstance);
ECS_COMPONENT_DEFINE(world, EcsAlertsActive);

ECS_TAG_DEFINE(world, EcsAlertInfo);
ECS_TAG_DEFINE(world, EcsAlertWarning);
ECS_TAG_DEFINE(world, EcsAlertError);
ECS_TAG_DEFINE(world, EcsAlertCritical);

ecs_add_id(world, ecs_id(EcsAlertsActive), EcsPrivate);

ecs_struct(world, {
Expand Down Expand Up @@ -34206,17 +33986,24 @@ int ecs_entity_to_json_buf(
while (ecs_map_next(&it)) {
flecs_json_next(buf);
flecs_json_object_push(buf);
ecs_entity_t a = ecs_map_key(&it);
ecs_entity_t ai = ecs_map_value(&it);
char *alert_name = ecs_get_fullpath(world, ai);
flecs_json_memberl(buf, "alert");
flecs_json_string(buf, alert_name);
ecs_os_free(alert_name);

ecs_entity_t severity_id = ecs_get_target(
world, a, ecs_id(EcsAlert), 0);
const char *severity = ecs_get_name(world, severity_id);

const EcsAlertInstance *alert = ecs_get(
world, ai, EcsAlertInstance);
if (alert) {
flecs_json_memberl(buf, "message");
flecs_json_string(buf, alert->message);
flecs_json_memberl(buf, "severity");
flecs_json_string(buf, severity);
}
flecs_json_object_pop(buf);
}
Expand Down Expand Up @@ -46154,6 +45941,10 @@ static ecs_entity_t ecs_default_lookup_path[2] = { 0, 0 };
ECS_COMPONENT_DECLARE(EcsAlert);
ECS_COMPONENT_DECLARE(EcsAlertInstance);
ECS_COMPONENT_DECLARE(EcsAlertsActive);
ECS_TAG_DECLARE(EcsAlertInfo);
ECS_TAG_DECLARE(EcsAlertWarning);
ECS_TAG_DECLARE(EcsAlertError);
ECS_TAG_DECLARE(EcsAlertCritical);
#endif

/* -- Private functions -- */
Expand Down Expand Up @@ -59707,15 +59498,6 @@ int flecs_entity_compare(
return (e1 > e2) - (e1 < e2);
}

int flecs_entity_compare_qsort(
const void *e1,
const void *e2)
{
ecs_entity_t v1 = *(ecs_entity_t*)e1;
ecs_entity_t v2 = *(ecs_entity_t*)e2;
return flecs_entity_compare(v1, NULL, v2, NULL);
}

uint64_t flecs_string_hash(
const void *ptr)
{
Expand Down
Loading

0 comments on commit 32e812c

Please sign in to comment.