@@ -130,13 +130,7 @@ struct traceeval_type {
};
/* Statistics about a given entry element */
-struct traceeval_stat {
- unsigned long long max;
- unsigned long long min;
- unsigned long long total;
- unsigned long long avg;
- unsigned long long std;
-};
+struct traceeval_stat;
/* Iterator over aggregated data */
struct traceeval_iterator;
@@ -160,4 +154,13 @@ int traceeval_query(struct traceeval *teval, const union traceeval_data *keys,
void traceeval_results_release(struct traceeval *teval,
union traceeval_data *results);
+struct traceeval_stat *traceeval_stat(struct traceeval *teval,
+ const union traceeval_data *keys,
+ struct traceeval_type *type);
+
+unsigned long long traceeval_stat_max(struct traceeval_stat *stat);
+unsigned long long traceeval_stat_min(struct traceeval_stat *stat);
+unsigned long long traceeval_stat_total(struct traceeval_stat *stat);
+unsigned long long traceeval_stat_count(struct traceeval_stat *stat);
+
#endif /* __LIBTRACEEVAL_HIST_H__ */
@@ -45,11 +45,20 @@ struct hash_table {
struct hash_iter iter;
};
+struct traceeval_stat {
+ unsigned long long max;
+ unsigned long long min;
+ unsigned long long total;
+ unsigned long long std;
+ size_t count;
+};
+
/* A key-value pair */
struct entry {
struct hash_item hash;
union traceeval_data *keys;
union traceeval_data *vals;
+ struct traceeval_stat *val_stats;
};
/* Histogram */
@@ -505,21 +505,85 @@ static int get_entry(struct traceeval *teval, const union traceeval_data *keys,
* Return 0 on success, -1 on error.
*/
static int copy_traceeval_data(struct traceeval_type *type,
- const union traceeval_data *orig,
- union traceeval_data *copy)
+ struct traceeval_stat *stat,
+ const union traceeval_data *orig,
+ union traceeval_data *copy)
{
+ unsigned long long val;
+
*copy = *orig;
- if (type->type == TRACEEVAL_TYPE_STRING) {
+ switch(type->type) {
+ case TRACEEVAL_TYPE_NUMBER:
+ if (type->flags & TRACEEVAL_FL_SIGNED)
+ val = (long long)copy->number;
+ else
+ val = (unsigned long long)copy->number;
+ break;
+
+ case TRACEEVAL_TYPE_NUMBER_64:
+ if (type->flags & TRACEEVAL_FL_SIGNED)
+ val = (long long)copy->number_64;
+ else
+ val = (unsigned long long)copy->number_64;
+ break;
+
+ case TRACEEVAL_TYPE_NUMBER_32:
+ if (type->flags & TRACEEVAL_FL_SIGNED)
+ val = (long long)copy->number_32;
+ else
+ val = (unsigned long long)copy->number_32;
+ break;
+
+ case TRACEEVAL_TYPE_NUMBER_16:
+ if (type->flags & TRACEEVAL_FL_SIGNED)
+ val = (long long)copy->number_16;
+ else
+ val = (unsigned long long)copy->number_16;
+ break;
+
+ case TRACEEVAL_TYPE_NUMBER_8:
+ if (type->flags & TRACEEVAL_FL_SIGNED)
+ val = (long long)copy->number_8;
+ else
+ val = (unsigned long long)copy->number_8;
+ break;
+
+ case TRACEEVAL_TYPE_STRING:
copy->string = NULL;
if (orig->string)
copy->string = strdup(orig->string);
- else
- return 0;
if (!copy->string)
return -1;
+ return 0;
+ default:
+ return 0;
+ }
+
+ if (!stat)
+ return 0;
+
+ if (!stat->count++) {
+ stat->max = val;
+ stat->min = val;
+ stat->total = val;
+ return 0;
+ }
+
+ if (type->flags & TRACEEVAL_FL_SIGNED) {
+ if ((long long)stat->max < (long long)val)
+ stat->max = val;
+ if ((long long)stat->min > (long long)val)
+ stat->min = val;
+ stat->total += (long long)val;
+ } else {
+ if (stat->max < val)
+ stat->max = val;
+ if (stat->min > val)
+ stat->min = val;
+ stat->total += val;
}
return 0;
@@ -548,6 +612,7 @@ static void data_release(size_t size, union traceeval_data **data,
*/
static int copy_traceeval_data_set(size_t size, struct traceeval_type *type,
const union traceeval_data *orig,
+ struct traceeval_stat *stats,
union traceeval_data **copy)
{
size_t i;
@@ -561,7 +626,8 @@ static int copy_traceeval_data_set(size_t size, struct traceeval_type *type,
return -1;
for (i = 0; i < size; i++) {
- if (copy_traceeval_data(type + i, orig + i, (*copy) + i))
+ if (copy_traceeval_data(type + i, stats ? stats + i : NULL,
+ orig + i, (*copy) + i))
goto fail;
}
@@ -604,7 +670,7 @@ int traceeval_query(struct traceeval *teval, const union traceeval_data *keys,
return check;
return copy_traceeval_data_set(teval->nr_val_types, teval->val_types,
- entry->vals, results);
+ entry->vals, NULL, results);
}
/*
@@ -659,18 +725,22 @@ static int create_entry(struct traceeval *teval,
union traceeval_data *new_vals;
struct entry *entry;
+ entry = create_hist_entry(teval, keys);
+ if (!entry)
+ return -1;
+
+ entry->val_stats = calloc(teval->nr_key_types, sizeof(*entry->val_stats));
+ if (!entry->val_stats)
+ goto fail_entry;
+
/* copy keys */
if (copy_traceeval_data_set(teval->nr_key_types, teval->key_types,
- keys, &new_keys) == -1)
- return -1;
+ keys, NULL, &new_keys) == -1)
+ goto fail_stats;
/* copy vals */
if (copy_traceeval_data_set(teval->nr_val_types, teval->val_types,
- vals, &new_vals) == -1)
- goto fail_vals;
-
- entry = create_hist_entry(teval, keys);
- if (!entry)
+ vals, entry->val_stats, &new_vals) == -1)
goto fail;
entry->keys = new_keys;
@@ -679,10 +749,13 @@ static int create_entry(struct traceeval *teval,
return 0;
fail:
- data_release(teval->nr_val_types, &new_vals, teval->val_types);
-
-fail_vals:
data_release(teval->nr_key_types, &new_keys, teval->key_types);
+
+fail_stats:
+ free(entry->val_stats);
+
+fail_entry:
+ free(entry);
return -1;
}
@@ -699,7 +772,7 @@ static int update_entry(struct traceeval *teval, struct entry *entry,
union traceeval_data *new_vals;
if (copy_traceeval_data_set(teval->nr_val_types, teval->val_types,
- vals, &new_vals) == -1)
+ vals, entry->val_stats, &new_vals) == -1)
return -1;
clean_data_set(entry->vals, teval->val_types, teval->nr_val_types);
@@ -707,6 +780,79 @@ static int update_entry(struct traceeval *teval, struct entry *entry,
return 0;
}
+struct traceeval_stat *traceeval_stat(struct traceeval *teval,
+ const union traceeval_data *keys,
+ struct traceeval_type *type)
+{
+ struct entry *entry;
+ int ret;
+
+ /* Only value numbers have stats */
+ if (!(type->flags & TRACEEVAL_FL_VALUE))
+ return NULL;
+
+ switch (type->type) {
+ case TRACEEVAL_TYPE_NUMBER:
+ case TRACEEVAL_TYPE_NUMBER_64:
+ case TRACEEVAL_TYPE_NUMBER_32:
+ case TRACEEVAL_TYPE_NUMBER_16:
+ case TRACEEVAL_TYPE_NUMBER_8:
+ break;
+ default:
+ return NULL;
+ }
+
+ ret = get_entry(teval, keys, &entry);
+ if (ret <= 0)
+ return NULL;
+
+ return &entry->val_stats[type->index];
+}
+
+/**
+ * traceeval_stat_max - return max value of stat
+ * @stat: The stat structure that holds the stats
+ *
+ * Returns the max value within @stat.
+ */
+unsigned long long traceeval_stat_max(struct traceeval_stat *stat)
+{
+ return stat->max;
+}
+
+/**
+ * traceeval_stat_min - return min value of stat
+ * @stat: The stat structure that holds the stats
+ *
+ * Returns the min value within @stat.
+ */
+unsigned long long traceeval_stat_min(struct traceeval_stat *stat)
+{
+ return stat->min;
+}
+
+/**
+ * traceeval_stat_total - return total value of stat
+ * @stat: The stat structure that holds the stats
+ *
+ * Returns the total value within @stat.
+ */
+unsigned long long traceeval_stat_total(struct traceeval_stat *stat)
+{
+ return stat->total;
+}
+
+/**
+ * traceeval_stat_count - return count value of stat
+ * @stat: The stat structure that holds the stats
+ *
+ * Returns the count value within @stat.
+ */
+unsigned long long traceeval_stat_count(struct traceeval_stat *stat)
+{
+ return stat->count;
+}
+
/*
* traceeval_insert - insert an item into the traceeval descriptor
* @teval: The descriptor to insert into