|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
b3514a |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
b3514a |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
b3514a |
* of the License, or (at your option) any later version.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
b3514a |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
b3514a |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
b3514a |
* GNU General Public License for more details.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
b3514a |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
b3514a |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
b3514a |
* 02110-1301, USA.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/workItemStats.h#2 $
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#ifndef WORK_ITEM_STATS_H
|
|
Packit Service |
b3514a |
#define WORK_ITEM_STATS_H
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "timeUtils.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "workQueue.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
enum {
|
|
Packit Service |
b3514a |
// Whether to enable tracking of per-work-function run-time stats.
|
|
Packit Service |
b3514a |
ENABLE_PER_FUNCTION_TIMING_STATS = 0,
|
|
Packit Service |
b3514a |
// How many work function/priority pairs to track call stats for
|
|
Packit Service |
b3514a |
NUM_WORK_QUEUE_ITEM_STATS = 18,
|
|
Packit Service |
b3514a |
};
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
typedef struct simpleStats {
|
|
Packit Service |
b3514a |
uint64_t count;
|
|
Packit Service |
b3514a |
uint64_t sum;
|
|
Packit Service |
b3514a |
uint64_t min;
|
|
Packit Service |
b3514a |
uint64_t max;
|
|
Packit Service |
b3514a |
} SimpleStats;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* We track numbers of work items handled (and optionally the
|
|
Packit Service |
b3514a |
* wall-clock time to run the work functions), broken down by
|
|
Packit Service |
b3514a |
* individual work functions (or alternate functions that the caller
|
|
Packit Service |
b3514a |
* wants recorded, like the VIO completion callback function if we're
|
|
Packit Service |
b3514a |
* just enqueueing a work function that invokes that indirectly) and
|
|
Packit Service |
b3514a |
* priority.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* The first part of this structure manages the function/priority
|
|
Packit Service |
b3514a |
* pairs, and is read frequently but updated rarely (once for each
|
|
Packit Service |
b3514a |
* pair, plus possibly spin lock contention).
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* The second part holds counters, and is updated often; different
|
|
Packit Service |
b3514a |
* parts are updated by various threads as described below. The last
|
|
Packit Service |
b3514a |
* element of each array, index NUM_WORK_QUEUE_ITEM_STATS, is updated
|
|
Packit Service |
b3514a |
* only if we have filled the arrays and can't add the current work
|
|
Packit Service |
b3514a |
* function/priority. See how the statTableIndex field is set in
|
|
Packit Service |
b3514a |
* workItemStats.c.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* All fields may additionally be read when reporting statistics
|
|
Packit Service |
b3514a |
* (including optionally reporting stats when the worker thread shuts
|
|
Packit Service |
b3514a |
* down), but that's rare and shouldn't significantly affect cache
|
|
Packit Service |
b3514a |
* contention issues.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* There is no "pending" count per work function here. For reporting
|
|
Packit Service |
b3514a |
* statistics, it can be approximated by looking at the other fields.
|
|
Packit Service |
b3514a |
* Do not rely on them being precise and synchronized, though.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
typedef struct kvdoWorkItemStatsFunctionTable {
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* The spin lock is used to protect .functions and .priorities
|
|
Packit Service |
b3514a |
* during updates. All three are modified by producers (enqueueing
|
|
Packit Service |
b3514a |
* threads) but only rarely. The .functions and .priorities arrays
|
|
Packit Service |
b3514a |
* are read by producers very frequently.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
spinlock_t lock;
|
|
Packit Service |
b3514a |
KvdoWorkFunction functions[NUM_WORK_QUEUE_ITEM_STATS];
|
|
Packit Service |
b3514a |
uint8_t priorities[NUM_WORK_QUEUE_ITEM_STATS];
|
|
Packit Service |
b3514a |
} KvdoWorkFunctionTable;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
typedef struct kvdoWorkItemStats {
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* Table of functions and priorities, for determining the index to
|
|
Packit Service |
b3514a |
* use into the counter arrays below.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This table is read by producers (usually multiple entries) for
|
|
Packit Service |
b3514a |
* every work item enqueued, and when reporting stats. It is updated
|
|
Packit Service |
b3514a |
* by producers, and only the first time a new (work-function,
|
|
Packit Service |
b3514a |
* priority) combination is seen.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
KvdoWorkFunctionTable functionTable;
|
|
Packit Service |
b3514a |
// Skip to (somewhere on) the next cache line
|
|
Packit Service |
b3514a |
char pad[CACHE_LINE_BYTES - sizeof(atomic64_t)];
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* The .enqueued field is updated by producers only, once per work
|
|
Packit Service |
b3514a |
* item processed; __sync operations are used to update these
|
|
Packit Service |
b3514a |
* values.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
atomic64_t enqueued[NUM_WORK_QUEUE_ITEM_STATS + 1];
|
|
Packit Service |
b3514a |
// Skip to (somewhere on) the next cache line
|
|
Packit Service |
b3514a |
char pad2[CACHE_LINE_BYTES - sizeof(atomic64_t)];
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* These values are updated only by the consumer (worker thread). We
|
|
Packit Service |
b3514a |
* overload the .times[].count field as a count of items processed,
|
|
Packit Service |
b3514a |
* so if we're not doing the optional processing-time tracking
|
|
Packit Service |
b3514a |
* (controlled via an option in workQueue.c), we need to explicitly
|
|
Packit Service |
b3514a |
* update the count.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* Since only one thread can ever update these values, no
|
|
Packit Service |
b3514a |
* synchronization is used.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
SimpleStats times[NUM_WORK_QUEUE_ITEM_STATS + 1];
|
|
Packit Service |
b3514a |
} KvdoWorkItemStats;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Initialize a statistics structure for tracking sample
|
|
Packit Service |
b3514a |
* values. Assumes the storage was already zeroed out at allocation
|
|
Packit Service |
b3514a |
* time.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline void initSimpleStats(SimpleStats *stats)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
// Assume other fields are initialized to zero at allocation.
|
|
Packit Service |
b3514a |
stats->min = UINT64_MAX;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Update the statistics being tracked for a new sample value.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
* @param value The new value to be folded in
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline void addSample(SimpleStats *stats, uint64_t value)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
stats->count++;
|
|
Packit Service |
b3514a |
stats->sum += value;
|
|
Packit Service |
b3514a |
if (stats->min > value) {
|
|
Packit Service |
b3514a |
stats->min = value;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
if (stats->max < value) {
|
|
Packit Service |
b3514a |
stats->max = value;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Return the average of the samples collected.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @return The average sample value
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline uint64_t getSampleAverage(const SimpleStats *stats)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
uint64_t slop = stats->count / 2;
|
|
Packit Service |
b3514a |
return (stats->sum + slop) / stats->count;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Update all work queue statistics (work-item and otherwise) after
|
|
Packit Service |
b3514a |
* enqueueing a work item.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
* @param item The work item enqueued
|
|
Packit Service |
b3514a |
* @param priority The work item's priority
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
void updateWorkItemStatsForEnqueue(KvdoWorkItemStats *stats,
|
|
Packit Service |
b3514a |
KvdoWorkItem *item,
|
|
Packit Service |
b3514a |
int priority);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Update all work queue statistics (work-item and otherwise) after enqueueing
|
|
Packit Service |
b3514a |
* a work item.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This is a very lightweight function (after optimizing away conditionals and
|
|
Packit Service |
b3514a |
* no-ops) and is called for every work item processed, hence the inline
|
|
Packit Service |
b3514a |
* definition.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This function requires that recordStartTime and
|
|
Packit Service |
b3514a |
* updateWorkItemStatsForWorkTime below both get called as well; in some cases
|
|
Packit Service |
b3514a |
* counters may be updated in updateWorkItemStatsForWorkTime rather than here.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
* @param item The work item enqueued
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline void updateWorkItemStatsForDequeue(KvdoWorkItemStats *stats,
|
|
Packit Service |
b3514a |
KvdoWorkItem *item)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
// The times[].count field is overloaded as a count of items
|
|
Packit Service |
b3514a |
// processed.
|
|
Packit Service |
b3514a |
if (!ENABLE_PER_FUNCTION_TIMING_STATS) {
|
|
Packit Service |
b3514a |
stats->times[item->statTableIndex].count++;
|
|
Packit Service |
b3514a |
} else {
|
|
Packit Service |
b3514a |
// In this case, updateWorkItemStatsForWorkTime will bump the counter.
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Record the starting time for processing a work item, if timing
|
|
Packit Service |
b3514a |
* stats are enabled and if we haven't run out of room for recording
|
|
Packit Service |
b3514a |
* stats in the table.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param index The work item's index into the internal array
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @return The current time, or zero
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline uint64_t recordStartTime(unsigned int index)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
return (ENABLE_PER_FUNCTION_TIMING_STATS ? currentTime(CLOCK_MONOTONIC) : 0);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Update the work queue statistics with the wall-clock time for
|
|
Packit Service |
b3514a |
* processing a work item, if timing stats are enabled and if we
|
|
Packit Service |
b3514a |
* haven't run out of room for recording stats in the table.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
* @param index The work item's index into the internal array
|
|
Packit Service |
b3514a |
* @param startTime The start time as reported by recordStartTime
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static inline void updateWorkItemStatsForWorkTime(KvdoWorkItemStats *stats,
|
|
Packit Service |
b3514a |
unsigned int index,
|
|
Packit Service |
b3514a |
uint64_t startTime)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
if (ENABLE_PER_FUNCTION_TIMING_STATS) {
|
|
Packit Service |
b3514a |
uint64_t endTime = currentTime(CLOCK_MONOTONIC);
|
|
Packit Service |
b3514a |
addSample(&stats->times[index], endTime - startTime);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Convert the pointer into a string representation, using a function
|
|
Packit Service |
b3514a |
* name if available.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param pointer The pointer to be converted
|
|
Packit Service |
b3514a |
* @param buffer The output buffer
|
|
Packit Service |
b3514a |
* @param bufferLength The size of the output buffer
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
char *getFunctionName(void *pointer, char *buffer, size_t bufferLength);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Dump statistics broken down by work function and priority into the
|
|
Packit Service |
b3514a |
* kernel log.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param stats The statistics structure
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
void logWorkItemStats(const KvdoWorkItemStats *stats);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Format counters for per-work-function stats for reporting via /sys.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param [in] stats The statistics structure
|
|
Packit Service |
b3514a |
* @param [out] buffer The output buffer
|
|
Packit Service |
b3514a |
* @param [in] length The size of the output buffer
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @return The size of the string actually written
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
size_t formatWorkItemStats(const KvdoWorkItemStats *stats,
|
|
Packit Service |
b3514a |
char *buffer,
|
|
Packit Service |
b3514a |
size_t length);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#endif // WORK_ITEM_STATS_H
|