summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/edgetpu-usage-stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edgetpu/edgetpu-usage-stats.c')
-rw-r--r--drivers/edgetpu/edgetpu-usage-stats.c243
1 files changed, 236 insertions, 7 deletions
diff --git a/drivers/edgetpu/edgetpu-usage-stats.c b/drivers/edgetpu/edgetpu-usage-stats.c
index 4c6dfcc..ba93d49 100644
--- a/drivers/edgetpu/edgetpu-usage-stats.c
+++ b/drivers/edgetpu/edgetpu-usage-stats.c
@@ -13,16 +13,36 @@
#include "edgetpu-kci.h"
#include "edgetpu-usage-stats.h"
+/* Max number of frequencies to support */
+#define EDGETPU_MAX_STATES 10
+
struct uid_entry {
int32_t uid;
- uint64_t time_in_state[EDGETPU_NUM_STATES];
+ uint64_t time_in_state[EDGETPU_MAX_STATES];
struct hlist_node node;
};
-static int tpu_state_map(uint32_t state)
+static int tpu_state_map(struct edgetpu_dev *etdev, uint32_t state)
{
- int i;
+ int i, idx = 0;
+
+ mutex_lock(&etdev->freq_lock);
+ /* Use frequency table if f/w already reported via usage_stats */
+ if (etdev->freq_table) {
+ for (i = etdev->freq_count - 1; i >= 0; i--) {
+ if (state == etdev->freq_table[i])
+ idx = i;
+ }
+ mutex_unlock(&etdev->freq_lock);
+ return idx;
+ }
+ mutex_unlock(&etdev->freq_lock);
+
+ /*
+ * use predefined state table in case of no f/w reported supported
+ * frequencies.
+ */
for (i = (EDGETPU_NUM_STATES - 1); i >= 0; i--) {
if (state >= edgetpu_active_states[i])
return i;
@@ -49,7 +69,7 @@ int edgetpu_usage_add(struct edgetpu_dev *etdev, struct tpu_usage *tpu_usage)
{
struct edgetpu_usage_stats *ustats = etdev->usage_stats;
struct uid_entry *uid_entry;
- int state = tpu_state_map(tpu_usage->power_state);
+ int state = tpu_state_map(etdev, tpu_usage->power_state);
if (!ustats)
return 0;
@@ -186,6 +206,39 @@ static void edgetpu_thread_stats_update(
mutex_unlock(&ustats->usage_stats_lock);
}
+/* Record new supported frequencies if reported by firmware */
+static void edgetpu_dvfs_frequency_update(struct edgetpu_dev *etdev, uint32_t frequency)
+{
+ uint32_t *freq_table, i;
+
+ mutex_lock(&etdev->freq_lock);
+ if (!etdev->freq_table) {
+ freq_table = kvmalloc(EDGETPU_MAX_STATES * sizeof(uint32_t), GFP_KERNEL);
+ if (!freq_table) {
+ etdev_warn(etdev, "Unable to create supported frequencies table");
+ goto out;
+ }
+ etdev->freq_count = 0;
+ etdev->freq_table = freq_table;
+ }
+
+ freq_table = etdev->freq_table;
+
+ for (i = 0; i < etdev->freq_count; i++) {
+ if (freq_table[i] == frequency)
+ goto out;
+ }
+
+ if (etdev->freq_count >= EDGETPU_MAX_STATES) {
+ etdev_warn(etdev, "Unable to record supported frequencies");
+ goto out;
+ }
+
+ freq_table[etdev->freq_count++] = frequency;
+out:
+ mutex_unlock(&etdev->freq_lock);
+}
+
void edgetpu_usage_stats_process_buffer(struct edgetpu_dev *etdev, void *buf)
{
struct edgetpu_usage_header *header = buf;
@@ -221,6 +274,10 @@ void edgetpu_usage_stats_process_buffer(struct edgetpu_dev *etdev, void *buf)
edgetpu_thread_stats_update(
etdev, &metric->thread_stats);
break;
+ case EDGETPU_METRIC_TYPE_DVFS_FREQUENCY_INFO:
+ edgetpu_dvfs_frequency_update(
+ etdev, metric->dvfs_frequency_info);
+ break;
default:
etdev_dbg(etdev, "%s: %d: skip unknown type=%u",
__func__, i, metric->type);
@@ -294,9 +351,18 @@ static ssize_t tpu_usage_show(struct device *dev,
/* uid: state0speed state1speed ... */
ret += scnprintf(buf, PAGE_SIZE, "uid:");
- for (i = 0; i < EDGETPU_NUM_STATES; i++)
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, " %d",
- edgetpu_states_display[i]);
+ mutex_lock(&etdev->freq_lock);
+ if (!etdev->freq_table) {
+ mutex_unlock(&etdev->freq_lock);
+ for (i = 0; i < EDGETPU_NUM_STATES; i++)
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, " %d",
+ edgetpu_states_display[i]);
+ } else {
+ for (i = 0; i < etdev->freq_count; i++)
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, " %d",
+ etdev->freq_table[i]);
+ mutex_unlock(&etdev->freq_lock);
+ }
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
@@ -570,6 +636,69 @@ static ssize_t hardware_preempt_count_store(struct device *dev, struct device_at
static DEVICE_ATTR(hardware_preempt_count, 0664, hardware_preempt_count_show,
hardware_preempt_count_store);
+static ssize_t hardware_ctx_save_time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_counter(etdev, EDGETPU_COUNTER_HARDWARE_CTX_SAVE_TIME_US);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t hardware_ctx_save_time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+
+ edgetpu_counter_clear(etdev, EDGETPU_COUNTER_HARDWARE_CTX_SAVE_TIME_US);
+ return count;
+}
+static DEVICE_ATTR(hardware_ctx_save_time, 0664, hardware_ctx_save_time_show,
+ hardware_ctx_save_time_store);
+
+static ssize_t scalar_fence_wait_time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_counter(etdev, EDGETPU_COUNTER_SCALAR_FENCE_WAIT_TIME_US);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t scalar_fence_wait_time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+
+ edgetpu_counter_clear(etdev, EDGETPU_COUNTER_SCALAR_FENCE_WAIT_TIME_US);
+ return count;
+}
+static DEVICE_ATTR(scalar_fence_wait_time, 0664, scalar_fence_wait_time_show,
+ scalar_fence_wait_time_store);
+
+static ssize_t long_suspend_count_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_counter(etdev, EDGETPU_COUNTER_LONG_SUSPEND);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t long_suspend_count_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+
+ edgetpu_counter_clear(etdev, EDGETPU_COUNTER_LONG_SUSPEND);
+ return count;
+}
+static DEVICE_ATTR(long_suspend_count, 0664, long_suspend_count_show,
+ long_suspend_count_store);
+
static ssize_t outstanding_commands_max_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -629,6 +758,93 @@ static ssize_t preempt_depth_max_store(
static DEVICE_ATTR(preempt_depth_max, 0664, preempt_depth_max_show,
preempt_depth_max_store);
+static ssize_t hardware_ctx_save_time_max_show(
+ struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_max_watermark(
+ etdev, EDGETPU_MAX_WATERMARK_HARDWARE_CTX_SAVE_TIME_US);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t hardware_ctx_save_time_max_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ struct edgetpu_usage_stats *ustats = etdev->usage_stats;
+
+ if (ustats) {
+ mutex_lock(&ustats->usage_stats_lock);
+ ustats->max_watermark[EDGETPU_MAX_WATERMARK_HARDWARE_CTX_SAVE_TIME_US] = 0;
+ mutex_unlock(&ustats->usage_stats_lock);
+ }
+
+ return count;
+}
+static DEVICE_ATTR(hardware_ctx_save_time_max, 0664, hardware_ctx_save_time_max_show,
+ hardware_ctx_save_time_max_store);
+
+static ssize_t scalar_fence_wait_time_max_show(
+ struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_max_watermark(
+ etdev, EDGETPU_MAX_WATERMARK_SCALAR_FENCE_WAIT_TIME_US);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t scalar_fence_wait_time_max_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ struct edgetpu_usage_stats *ustats = etdev->usage_stats;
+
+ if (ustats) {
+ mutex_lock(&ustats->usage_stats_lock);
+ ustats->max_watermark[EDGETPU_MAX_WATERMARK_SCALAR_FENCE_WAIT_TIME_US] = 0;
+ mutex_unlock(&ustats->usage_stats_lock);
+ }
+
+ return count;
+}
+static DEVICE_ATTR(scalar_fence_wait_time_max, 0664, scalar_fence_wait_time_max_show,
+ scalar_fence_wait_time_max_store);
+
+static ssize_t suspend_time_max_show(
+ struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ int64_t val;
+
+ val = edgetpu_usage_get_max_watermark(
+ etdev, EDGETPU_MAX_WATERMARK_SUSPEND_TIME_US);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t suspend_time_max_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct edgetpu_dev *etdev = dev_get_drvdata(dev);
+ struct edgetpu_usage_stats *ustats = etdev->usage_stats;
+
+ if (ustats) {
+ mutex_lock(&ustats->usage_stats_lock);
+ ustats->max_watermark[EDGETPU_MAX_WATERMARK_SUSPEND_TIME_US] = 0;
+ mutex_unlock(&ustats->usage_stats_lock);
+ }
+
+ return count;
+}
+static DEVICE_ATTR(suspend_time_max, 0664, suspend_time_max_show,
+ suspend_time_max_store);
+
static ssize_t fw_thread_stats_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -681,8 +897,14 @@ static struct attribute *usage_stats_dev_attrs[] = {
&dev_attr_param_cache_miss_count.attr,
&dev_attr_context_preempt_count.attr,
&dev_attr_hardware_preempt_count.attr,
+ &dev_attr_hardware_ctx_save_time.attr,
+ &dev_attr_scalar_fence_wait_time.attr,
+ &dev_attr_long_suspend_count.attr,
&dev_attr_outstanding_commands_max.attr,
&dev_attr_preempt_depth_max.attr,
+ &dev_attr_hardware_ctx_save_time_max.attr,
+ &dev_attr_scalar_fence_wait_time_max.attr,
+ &dev_attr_suspend_time_max.attr,
&dev_attr_fw_thread_stats.attr,
NULL,
};
@@ -721,6 +943,13 @@ void edgetpu_usage_stats_exit(struct edgetpu_dev *etdev)
if (ustats) {
usage_stats_remove_uids(ustats);
device_remove_group(etdev->dev, &usage_stats_attr_group);
+ /* free the frequency table if allocated */
+ mutex_lock(&etdev->freq_lock);
+ if (etdev->freq_table)
+ kvfree(etdev->freq_table);
+ etdev->freq_table = NULL;
+ etdev->freq_count = 0;
+ mutex_unlock(&etdev->freq_lock);
}
etdev_dbg(etdev, "%s exit\n", __func__);