libsensors: Get rid of arbitrary limit on per-type sensor count

When gathering the attributes of each hwmon chip, libsensors uses a
temporary structure in memory to order and group all the attributes
into features. This temporary structure used to be a single array with
room for every possible attribute/subfeature. While simple, this
approach required to predefine a maximum number of per-type sensor
that could be handled.

In order to get rid of this arbitrary limit, which we hit and had to
raise three times already, I changed the temporary structure to an
array of dynamically allocated per-type subattribute arrays. This lets
us not allocate any memory for types which aren't implemented by a
given chip, and more importantly, this lets us reallocate room for
more attributes of a given type as needed.

I decided to allocate chunks of 8 attributes at a time, as this seemed
a good compromise between two frequent reallocations and
over-provisioning. It could be tweaked if needed.

Icing on the cake, I benchmarked this change on two different systems
and it results in performance gains. The total heap usage as reported
by valgrind is down by 50% on average, with peak memory consumption
(as reported by valgrind's massif) also down by 43% on average. The
total instructions count (as reported by valgrind's callgrind) is down
by 11% on average, with measured execution time also down by a few
percents. Valgrind rocks, BTW.

I have some ideas to optimize the memory allocations further, but I do
not expect such a huge gain from them. They may not even improve peak
memory consumption as massif shows the peak is somewhere else now at
least in some cases.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Jean Delvare
2014-01-25 09:41:03 -08:00
committed by Guenter Roeck
parent 3b04ee5cba
commit b7b2c45789
2 changed files with 78 additions and 78 deletions
+1
View File
@@ -146,6 +146,7 @@ typedef enum sensors_feature_type {
SENSORS_FEATURE_INTRUSION = 0x11,
SENSORS_FEATURE_MAX_OTHER,
SENSORS_FEATURE_BEEP_ENABLE = 0x18,
SENSORS_FEATURE_MAX,
SENSORS_FEATURE_UNKNOWN = INT_MAX,
} sensors_feature_type;
+77 -78
View File
@@ -138,21 +138,8 @@ static int sysfs_foreach_busdev(const char *bus_type,
char sensors_sysfs_mount[NAME_MAX];
#define MAX_MAIN_SENSOR_TYPES (SENSORS_FEATURE_MAX_MAIN - SENSORS_FEATURE_IN)
#define MAX_OTHER_SENSOR_TYPES (SENSORS_FEATURE_MAX_OTHER - SENSORS_FEATURE_VID)
#define MAX_SENSORS_PER_TYPE 33
/* max_subfeatures is now computed dynamically */
#define FEATURE_SIZE (max_subfeatures * 2)
#define FEATURE_TYPE_SIZE (MAX_SENSORS_PER_TYPE * FEATURE_SIZE)
/*
* Room for all 7 main types (in, fan, temp, power, energy, current, humidity)
* and 2 other types (VID, intrusion) with all their subfeatures + misc features
*/
#define SUB_OFFSET_OTHER (MAX_MAIN_SENSOR_TYPES * FEATURE_TYPE_SIZE)
#define SUB_OFFSET_MISC (SUB_OFFSET_OTHER + \
MAX_OTHER_SENSOR_TYPES * FEATURE_TYPE_SIZE)
#define ALL_POSSIBLE_SUBFEATURES (SUB_OFFSET_MISC + 1)
static
int get_type_scaling(sensors_subfeature_type type)
@@ -432,7 +419,10 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
static int max_subfeatures;
DIR *dir;
struct dirent *ent;
sensors_subfeature *all_subfeatures;
struct {
int count;
sensors_subfeature *sf;
} all_types[SENSORS_FEATURE_MAX];
sensors_subfeature *dyn_subfeatures;
sensors_feature *dyn_features;
sensors_feature_type ftype;
@@ -445,13 +435,10 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
if (!max_subfeatures)
max_subfeatures = sensors_compute_max();
/* We use a large sparse table at first to store all found
subfeatures, so that we can store them sorted at type and index
and then later create a dense sorted table. */
all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
sizeof(sensors_subfeature));
if (!all_subfeatures)
sensors_fatal_error(__func__, "Out of memory");
/* We use a set of large sparse tables at first (one per main
feature type present) to store all found subfeatures, so that we
can store them sorted and then later create a dense sorted table. */
memset(&all_types, 0, sizeof(all_types));
while ((ent = readdir(dir))) {
char *name;
@@ -482,37 +469,43 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
break;
}
if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
/* More sensors of one type than MAX_SENSORS_PER_TYPE,
we have to ignore it */
/* Skip invalid entries */
if (nr < 0) {
#ifdef DEBUG
sensors_fatal_error(__func__,
"Increase MAX_SENSORS_PER_TYPE!");
"Invalid channel number!");
#endif
continue;
}
/* "calculate" a place to store the subfeature in our sparse,
sorted table */
switch (ftype) {
case SENSORS_FEATURE_VID:
case SENSORS_FEATURE_INTRUSION:
i = SUB_OFFSET_OTHER +
(ftype - SENSORS_FEATURE_VID) * FEATURE_TYPE_SIZE +
nr * FEATURE_SIZE + (sftype & 0xFF);
break;
case SENSORS_FEATURE_BEEP_ENABLE:
i = SUB_OFFSET_MISC +
(ftype - SENSORS_FEATURE_BEEP_ENABLE);
break;
default:
i = ftype * FEATURE_TYPE_SIZE +
nr * FEATURE_SIZE +
((sftype & 0x80) >> 7) * max_subfeatures +
(sftype & 0x7F);
/* (Re-)allocate memory if needed */
if (all_types[ftype].count < nr + 1) {
int old_count = all_types[ftype].count;
while (all_types[ftype].count < nr + 1)
all_types[ftype].count += 8;
all_types[ftype].sf = realloc(all_types[ftype].sf,
all_types[ftype].count *
FEATURE_SIZE *
sizeof(sensors_subfeature));
if (!all_types[ftype].sf)
sensors_fatal_error(__func__, "Out of memory");
memset(all_types[ftype].sf + old_count * FEATURE_SIZE,
0, (all_types[ftype].count - old_count) *
FEATURE_SIZE * sizeof(sensors_subfeature));
}
if (all_subfeatures[i].name) {
/* "calculate" a place to store the subfeature in our sparse,
sorted table */
if (ftype < SENSORS_FEATURE_VID)
i = nr * FEATURE_SIZE +
((sftype & 0x80) >> 7) * max_subfeatures +
(sftype & 0x7F);
else
i = nr * FEATURE_SIZE + (sftype & 0xFF);
if (all_types[ftype].sf[i].name) {
#ifdef DEBUG
sensors_fatal_error(__func__, "Duplicate subfeature");
#endif
@@ -520,15 +513,16 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
}
/* fill in the subfeature members */
all_subfeatures[i].type = sftype;
all_subfeatures[i].name = strdup(name);
if (!all_subfeatures[i].name)
all_types[ftype].sf[i].type = sftype;
all_types[ftype].sf[i].name = strdup(name);
if (!all_types[ftype].sf[i].name)
sensors_fatal_error(__func__, "Out of memory");
/* Other and misc subfeatures are never scaled */
if (sftype < SENSORS_SUBFEATURE_VID && !(sftype & 0x80))
all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
all_types[ftype].sf[i].flags |= SENSORS_COMPUTE_MAPPING;
all_types[ftype].sf[i].flags |=
sensors_get_attr_mode(dev_path, name);
sfnum++;
}
@@ -540,14 +534,16 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
}
/* How many main features? */
prev_slot = -1;
for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
if (!all_subfeatures[i].name)
continue;
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
prev_slot = -1;
for (i = 0; i < all_types[ftype].count * FEATURE_SIZE; i++) {
if (!all_types[ftype].sf[i].name)
continue;
if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
fnum++;
prev_slot = i / FEATURE_SIZE;
if (i / FEATURE_SIZE != prev_slot) {
fnum++;
prev_slot = i / FEATURE_SIZE;
}
}
}
@@ -559,30 +555,32 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
/* Copy from the sparse array to the compact array */
sfnum = 0;
fnum = -1;
prev_slot = -1;
for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
if (!all_subfeatures[i].name)
continue;
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
prev_slot = -1;
for (i = 0; i < all_types[ftype].count * FEATURE_SIZE; i++) {
if (!all_types[ftype].sf[i].name)
continue;
/* New main feature? */
if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
ftype = all_subfeatures[i].type >> 8;
fnum++;
prev_slot = i / FEATURE_SIZE;
/* New main feature? */
if (i / FEATURE_SIZE != prev_slot) {
fnum++;
prev_slot = i / FEATURE_SIZE;
dyn_features[fnum].name = get_feature_name(ftype,
all_subfeatures[i].name);
dyn_features[fnum].number = fnum;
dyn_features[fnum].first_subfeature = sfnum;
dyn_features[fnum].type = ftype;
dyn_features[fnum].name =
get_feature_name(ftype,
all_types[ftype].sf[i].name);
dyn_features[fnum].number = fnum;
dyn_features[fnum].first_subfeature = sfnum;
dyn_features[fnum].type = ftype;
}
dyn_subfeatures[sfnum] = all_types[ftype].sf[i];
dyn_subfeatures[sfnum].number = sfnum;
/* Back to the feature */
dyn_subfeatures[sfnum].mapping = fnum;
sfnum++;
}
dyn_subfeatures[sfnum] = all_subfeatures[i];
dyn_subfeatures[sfnum].number = sfnum;
/* Back to the feature */
dyn_subfeatures[sfnum].mapping = fnum;
sfnum++;
}
chip->subfeature = dyn_subfeatures;
@@ -591,7 +589,8 @@ static int sensors_read_dynamic_chip(sensors_chip_features *chip,
chip->feature_count = ++fnum;
exit_free:
free(all_subfeatures);
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++)
free(all_types[ftype].sf);
return 0;
}