Skip to content

Commit

Permalink
gcov: Make TOPN counter dynamically allocated
Browse files Browse the repository at this point in the history
* from gcc-mirror/gcc@871e5ad
  remove USE_ATOMIC usage
  use kmalloc instead of xmalloc

Signed-off-by: Diaz1401 <[email protected]>
  • Loading branch information
Diaz1401 committed Jun 30, 2023
1 parent 70373f3 commit 693b194
Showing 1 changed file with 68 additions and 29 deletions.
97 changes: 68 additions & 29 deletions kernel/gcov/gcc_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <stdlib.h>
#include "gcov.h"

/*
Expand Down Expand Up @@ -86,8 +87,72 @@ void __gcov_exit(void)
EXPORT_SYMBOL(__gcov_exit);

#ifdef CONFIG_PGO_KERNEL
/* Number of top N value histogram. */
#define GCOV_TOPN_VALUES 4

/* Maximum number of tracked TOP N value profiles. */
#define GCOV_TOPN_MAXIMUM_TRACKED_VALUES 32

/* GCOV key-value pair linked list type. */
struct gcov_kvp {
gcov_type value;
gcov_type count;
struct gcov_kvp *next;
};

static inline void gcov_counter_add(gcov_type *counter, gcov_type value)
{
*counter += value;
}

static inline int gcov_counter_set_if_null(gcov_type *counter, struct gcov_kvp *node)
{
*counter = (intptr_t)node;
return 1;
}

static inline void gcov_topn_add_value(gcov_type *counters, gcov_type value, gcov_type count,
int increment_total)
{
if (increment_total)
gcov_counter_add(&counters[0], 1);

struct gcov_kvp *prev_node = NULL;
struct gcov_kvp *minimal_node = NULL;
struct gcov_kvp *current_node = (struct gcov_kvp *)counters[2];

while (current_node) {
if (current_node->value == value) {
gcov_counter_add(&current_node->count, count);
return;
}

if (minimal_node == NULL || current_node->count < minimal_node->count)
minimal_node = current_node;

prev_node = current_node;
current_node = current_node->next;
}

if (counters[1] == GCOV_TOPN_MAXIMUM_TRACKED_VALUES) {
if (--minimal_node->count < count) {
minimal_node->value = value;
minimal_node->count = count;
}
} else {
struct gcov_kvp *new_node = (struct gcov_kvp *)kmalloc(sizeof(struct gcov_kvp), GFP_KERNEL);
new_node->value = value;
new_node->count = count;

int success = 0;
if (!counters[2])
success = gcov_counter_set_if_null(&counters[2], new_node);
else if (prev_node && !prev_node->next)
success = gcov_counter_set_if_null((gcov_type *)&prev_node->next, new_node);

/* Increment number of nodes. */
if (success)
gcov_counter_add(&counters[1], 1);
}
}

void __gcov_merge_topn(gcov_type *counters, unsigned int n_counters)
{
Expand All @@ -114,33 +179,7 @@ EXPORT_SYMBOL(__gcov_time_profiler_counter);
static inline void __gcov_topn_values_profiler_body(gcov_type *counters,
gcov_type value)
{
int empty_counter = -1;
unsigned int i;

counters[0]++;
++counters;

/* First try to find an existing value. */
for (i = 0; i < GCOV_TOPN_VALUES; i++)
if (value == counters[2 * i]) {
counters[2 * i + 1] += GCOV_TOPN_VALUES;
return;
} else if (counters[2 * i + 1] <= 0)
empty_counter = i;

/* Find an empty slot for a new value. */
if (empty_counter != -1) {
counters[2 * empty_counter] = value;
counters[2 * empty_counter + 1] = GCOV_TOPN_VALUES;
return;
}

/*
* We haven't found an empty slot, then decrement all
* counter values by one.
*/
for (i = 0; i < GCOV_TOPN_VALUES; i++)
counters[2 * i + 1]--;
gcov_topn_add_value(counters, value, 1, 1);
}

void __gcov_topn_values_profiler(gcov_type *counters, gcov_type value)
Expand Down

0 comments on commit 693b194

Please sign in to comment.