From 3fb6a7b46ea663c0cbece30b7979de1fc9a2b692 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 28 Jan 2021 19:19:26 +0100 Subject: [PATCH] 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. --- include/haproxy/activity-t.h | 13 +++++++++++++ include/haproxy/activity.h | 27 +++++++++++++++++++++++++++ src/activity.c | 2 ++ 3 files changed, 42 insertions(+) diff --git a/include/haproxy/activity-t.h b/include/haproxy/activity-t.h index 072b9cac2..328bde8bd 100644 --- a/include/haproxy/activity-t.h +++ b/include/haproxy/activity-t.h @@ -74,6 +74,19 @@ struct activity { 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 1a7361979..42569f203 100644 --- a/include/haproxy/activity.h +++ b/include/haproxy/activity.h @@ -22,6 +22,7 @@ #ifndef _HAPROXY_ACTIVITY_H #define _HAPROXY_ACTIVITY_H +#include #include #include #include @@ -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 @@ static inline void activity_count_runtime() } } +/* Computes the index of function pointer for use with sched_activity[] + * or any other similar array passed in , 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 79aad3e1c..0d64a3659 100644 --- a/src/activity.c +++ b/src/activity.c @@ -27,6 +27,8 @@ unsigned long task_profiling_mask = 0; /* 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 * is half-milliseconds.