MINOR: activity: declare a new structure to collect per-function activity
The new sched_activity structure will be used to collect task-level
activity based on the target function. The principle is to declare a
large enough array to make collisions rare (256 entries), and hash
the function pointer using a reduced XXH to decide where to store the
stats. On first computation an entry is definitely assigned to the
array and it's done atomically. A special entry (0) is used to store
collisions ("others"). The goal is to make it easy and inexpensive for
the scheduler code to use these to store #calls, cpu_time and lat_time
for each task.
diff --git a/include/haproxy/activity-t.h b/include/haproxy/activity-t.h
index 072b9ca..328bde8 100644
--- a/include/haproxy/activity-t.h
+++ b/include/haproxy/activity-t.h
@@ -74,6 +74,19 @@
char __end[0] __attribute__((aligned(64))); // align size to 64.
};
+
+/* global profiling stats from the scheduler: each entry corresponds to a
+ * task or tasklet ->process function pointer, with a number of calls and
+ * a total time. Each entry is unique, except entry 0 which is for colliding
+ * hashes (i.e. others). All of these must be accessed atomically.
+ */
+struct sched_activity {
+ const void *func;
+ uint64_t calls;
+ uint64_t cpu_time;
+ uint64_t lat_time;
+};
+
#endif /* _HAPROXY_ACTIVITY_T_H */
/*
diff --git a/include/haproxy/activity.h b/include/haproxy/activity.h
index 1a73619..42569f2 100644
--- a/include/haproxy/activity.h
+++ b/include/haproxy/activity.h
@@ -22,6 +22,7 @@
#ifndef _HAPROXY_ACTIVITY_H
#define _HAPROXY_ACTIVITY_H
+#include <import/xxhash.h>
#include <haproxy/activity-t.h>
#include <haproxy/api.h>
#include <haproxy/freq_ctr.h>
@@ -30,6 +31,7 @@
extern unsigned int profiling;
extern unsigned long task_profiling_mask;
extern struct activity activity[MAX_THREADS];
+extern struct sched_activity sched_activity[256];
void report_stolen_time(uint64_t stolen);
@@ -88,6 +90,31 @@
}
}
+/* Computes the index of function pointer <func> for use with sched_activity[]
+ * or any other similar array passed in <array>, and returns a pointer to the
+ * entry after having atomically assigned it to this function pointer. Note
+ * that in case of collision, the first entry is returned instead ("other").
+ */
+static inline struct sched_activity *sched_activity_entry(struct sched_activity *array, const void *func)
+{
+ uint64_t hash = XXH64_avalanche(XXH64_mergeRound((size_t)func, (size_t)func));
+ struct sched_activity *ret;
+ const void *old = NULL;
+
+ hash ^= (hash >> 32);
+ hash ^= (hash >> 16);
+ hash ^= (hash >> 8);
+ hash &= 0xff;
+ ret = &array[hash];
+
+ if (likely(ret->func == func))
+ return ret;
+
+ if (HA_ATOMIC_CAS(&ret->func, &old, func))
+ return ret;
+
+ return array;
+}
#endif /* _HAPROXY_ACTIVITY_H */
diff --git a/src/activity.c b/src/activity.c
index 79aad3e..0d64a36 100644
--- a/src/activity.c
+++ b/src/activity.c
@@ -27,6 +27,8 @@
/* One struct per thread containing all collected measurements */
struct activity activity[MAX_THREADS] __attribute__((aligned(64))) = { };
+/* One struct per function pointer hash entry (256 values, 0=collision) */
+struct sched_activity sched_activity[256] __attribute__((aligned(64))) = { };
/* Updates the current thread's statistics about stolen CPU time. The unit for
* <stolen> is half-milliseconds.