1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-26 04:51:17 +02:00
nman external-symbol improvements
Driver model memory-usage reporting
patman test-reporting improvements
Add bloblist design goals
This commit is contained in:
Tom Rini
2022-07-08 14:39:07 -04:00
59 changed files with 1694 additions and 380 deletions

View File

@@ -75,6 +75,27 @@ config DM_DEBUG
help
Say Y here if you want to compile in debug messages in DM core.
config DM_STATS
bool "Collect and show driver model stats"
depends on DM
default y if SANDBOX
help
Enable this to collect and display memory statistics about driver
model. This can help to figure out where all the memory is going and
to find optimisations.
To display the memory stats, use the 'dm mem' command.
config SPL_DM_STATS
bool "Collect and show driver model stats in SPL"
depends on DM_SPL
help
Enable this to collect and display memory statistics about driver
model. This can help to figure out where all the memory is going and
to find optimisations.
The stats are displayed just before SPL boots to the next phase.
config DM_DEVICE_REMOVE
bool "Support device removal"
depends on DM

View File

@@ -29,7 +29,7 @@ int device_chld_unbind(struct udevice *dev, struct driver *drv)
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
device_foreach_child_safe(pos, n, dev) {
if (drv && (pos->driver != drv))
continue;
@@ -52,7 +52,7 @@ int device_chld_remove(struct udevice *dev, struct driver *drv,
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
device_foreach_child_safe(pos, n, dev) {
int ret;
if (drv && (pos->driver != drv))

View File

@@ -284,8 +284,7 @@ int device_reparent(struct udevice *dev, struct udevice *new_parent)
assert(dev);
assert(new_parent);
list_for_each_entry_safe(pos, n, &dev->parent->child_head,
sibling_node) {
device_foreach_child_safe(pos, n, dev->parent) {
if (pos->driver != dev->driver)
continue;
@@ -675,6 +674,71 @@ void *dev_get_parent_priv(const struct udevice *dev)
return dm_priv_to_rw(dev->parent_priv_);
}
void *dev_get_attach_ptr(const struct udevice *dev, enum dm_tag_t tag)
{
switch (tag) {
case DM_TAG_PLAT:
return dev_get_plat(dev);
case DM_TAG_PARENT_PLAT:
return dev_get_parent_plat(dev);
case DM_TAG_UC_PLAT:
return dev_get_uclass_plat(dev);
case DM_TAG_PRIV:
return dev_get_priv(dev);
case DM_TAG_PARENT_PRIV:
return dev_get_parent_priv(dev);
case DM_TAG_UC_PRIV:
return dev_get_uclass_priv(dev);
default:
return NULL;
}
}
int dev_get_attach_size(const struct udevice *dev, enum dm_tag_t tag)
{
const struct udevice *parent = dev_get_parent(dev);
const struct uclass *uc = dev->uclass;
const struct uclass_driver *uc_drv = uc->uc_drv;
const struct driver *parent_drv = NULL;
int size = 0;
if (parent)
parent_drv = parent->driver;
switch (tag) {
case DM_TAG_PLAT:
size = dev->driver->plat_auto;
break;
case DM_TAG_PARENT_PLAT:
if (parent) {
size = parent_drv->per_child_plat_auto;
if (!size)
size = parent->uclass->uc_drv->per_child_plat_auto;
}
break;
case DM_TAG_UC_PLAT:
size = uc_drv->per_device_plat_auto;
break;
case DM_TAG_PRIV:
size = dev->driver->priv_auto;
break;
case DM_TAG_PARENT_PRIV:
if (parent) {
size = parent_drv->per_child_auto;
if (!size)
size = parent->uclass->uc_drv->per_child_auto;
}
break;
case DM_TAG_UC_PRIV:
size = uc_drv->per_device_auto;
break;
default:
break;
}
return size;
}
static int device_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
{
@@ -724,7 +788,7 @@ int device_get_child(const struct udevice *parent, int index,
{
struct udevice *dev;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (!index--)
return device_get_device_tail(dev, 0, devp);
}
@@ -737,7 +801,7 @@ int device_get_child_count(const struct udevice *parent)
struct udevice *dev;
int count = 0;
list_for_each_entry(dev, &parent->child_head, sibling_node)
device_foreach_child(dev, parent)
count++;
return count;
@@ -748,7 +812,7 @@ int device_get_decendent_count(const struct udevice *parent)
const struct udevice *dev;
int count = 1;
list_for_each_entry(dev, &parent->child_head, sibling_node)
device_foreach_child(dev, parent)
count += device_get_decendent_count(dev);
return count;
@@ -761,7 +825,7 @@ int device_find_child_by_seq(const struct udevice *parent, int seq,
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (dev->seq_ == seq) {
*devp = dev;
return 0;
@@ -790,7 +854,7 @@ int device_find_child_by_of_offset(const struct udevice *parent, int of_offset,
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (dev_of_offset(dev) == of_offset) {
*devp = dev;
return 0;
@@ -819,7 +883,7 @@ static struct udevice *_device_find_global_by_ofnode(struct udevice *parent,
if (ofnode_equal(dev_ofnode(parent), ofnode))
return parent;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
found = _device_find_global_by_ofnode(dev, ofnode);
if (found)
return found;
@@ -897,7 +961,7 @@ int device_find_first_inactive_child(const struct udevice *parent,
struct udevice *dev;
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (!device_active(dev) &&
device_get_uclass_id(dev) == uclass_id) {
*devp = dev;
@@ -915,7 +979,7 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
struct udevice *dev;
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (device_get_uclass_id(dev) == uclass_id) {
*devp = dev;
return 0;
@@ -932,7 +996,7 @@ int device_find_child_by_namelen(const struct udevice *parent, const char *name,
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
device_foreach_child(dev, parent) {
if (!strncmp(dev->name, name, len) &&
strlen(dev->name) == len) {
*devp = dev;

View File

@@ -232,7 +232,7 @@ static void dump_resources(struct udevice *dev, int depth)
(unsigned long)dr->size, dr->name,
devres_phase_name[dr->phase]);
list_for_each_entry(child, &dev->child_head, sibling_node)
device_foreach_child(child, dev)
dump_resources(child, depth + 1);
}

View File

@@ -39,13 +39,13 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
printf("%s\n", dev->name);
list_for_each_entry(child, &dev->child_head, sibling_node) {
device_foreach_child(child, dev) {
is_last = list_is_last(&child->sibling_node, &dev->child_head);
show_devices(child, depth + 1, (last_flag << 1) | is_last);
}
}
void dm_dump_all(void)
void dm_dump_tree(void)
{
struct udevice *root;
@@ -89,8 +89,6 @@ void dm_dump_uclass(void)
continue;
printf("uclass %d: %s\n", id, uc->uc_drv->name);
if (list_empty(&uc->dev_head))
continue;
uclass_foreach_dev(dev, uc) {
dm_display_line(dev, i);
i++;
@@ -171,8 +169,79 @@ void dm_dump_static_driver_info(void)
puts("Driver Address\n");
puts("---------------------------------\n");
for (entry = drv; entry != drv + n_ents; entry++) {
printf("%-25.25s @%08lx\n", entry->name,
(ulong)map_to_sysmem(entry->plat));
}
for (entry = drv; entry != drv + n_ents; entry++)
printf("%-25.25s %p\n", entry->name, entry->plat);
}
void dm_dump_mem(struct dm_stats *stats)
{
int total, total_delta;
int i;
/* Support SPL printf() */
printf("Struct sizes: udevice %x, driver %x, uclass %x, uc_driver %x\n",
(int)sizeof(struct udevice), (int)sizeof(struct driver),
(int)sizeof(struct uclass), (int)sizeof(struct uclass_driver));
printf("Memory: device %x:%x, device names %x, uclass %x:%x\n",
stats->dev_count, stats->dev_size, stats->dev_name_size,
stats->uc_count, stats->uc_size);
printf("\n");
printf("%-15s %5s %5s %5s %5s %5s\n", "Attached type", "Count",
"Size", "Cur", "Tags", "Save");
printf("%-15s %5s %5s %5s %5s %5s\n", "---------------", "-----",
"-----", "-----", "-----", "-----");
total_delta = 0;
for (i = 0; i < DM_TAG_ATTACH_COUNT; i++) {
int cur_size, new_size, delta;
cur_size = stats->dev_count * sizeof(struct udevice);
new_size = stats->dev_count * (sizeof(struct udevice) -
sizeof(void *));
/*
* Let's assume we can fit each dmtag_node into 32 bits. We can
* limit the 'tiny tags' feature to SPL with
* CONFIG_SPL_SYS_MALLOC_F_LEN <= 64KB, so needing 14 bits to
* point to anything in that region (with 4-byte alignment).
* So:
* 4 bits for tag
* 14 bits for offset of dev
* 14 bits for offset of data
*/
new_size += stats->attach_count[i] * sizeof(u32);
delta = cur_size - new_size;
total_delta += delta;
printf("%-16s %5x %6x %6x %6x %6x (%d)\n", tag_get_name(i),
stats->attach_count[i], stats->attach_size[i],
cur_size, new_size, delta > 0 ? delta : 0, delta);
}
printf("%-16s %5x %6x\n", "uclass", stats->uc_attach_count,
stats->uc_attach_size);
printf("%-16s %5x %6x %5s %5s %6x (%d)\n", "Attached total",
stats->attach_count_total + stats->uc_attach_count,
stats->attach_size_total + stats->uc_attach_size, "", "",
total_delta > 0 ? total_delta : 0, total_delta);
printf("%-16s %5x %6x\n", "tags", stats->tag_count, stats->tag_size);
printf("\n");
printf("Total size: %x (%d)\n", stats->total_size, stats->total_size);
printf("\n");
total = stats->total_size;
total -= total_delta;
printf("With tags: %x (%d)\n", total, total);
/* Use singly linked lists in struct udevice (3 nodes in each) */
total -= sizeof(void *) * 3 * stats->dev_count;
printf("- singly-linked: %x (%d)\n", total, total);
/* Use an index into the struct_driver list instead of a pointer */
total = total + stats->dev_count * (1 - sizeof(void *));
printf("- driver index: %x (%d)\n", total, total);
/* Same with the uclass */
total = total + stats->dev_count * (1 - sizeof(void *));
printf("- uclass index: %x (%d)\n", total, total);
/* Drop the device name */
printf("Drop device name (not SRAM): %x (%d)\n", stats->dev_name_size,
stats->dev_name_size);
}

View File

@@ -449,6 +449,59 @@ void dm_get_stats(int *device_countp, int *uclass_countp)
*uclass_countp = uclass_get_count();
}
void dev_collect_stats(struct dm_stats *stats, const struct udevice *parent)
{
const struct udevice *dev;
int i;
stats->dev_count++;
stats->dev_size += sizeof(struct udevice);
stats->dev_name_size += strlen(parent->name) + 1;
for (i = 0; i < DM_TAG_ATTACH_COUNT; i++) {
int size = dev_get_attach_size(parent, i);
if (size ||
(i == DM_TAG_DRIVER_DATA && parent->driver_data)) {
stats->attach_count[i]++;
stats->attach_size[i] += size;
stats->attach_count_total++;
stats->attach_size_total += size;
}
}
list_for_each_entry(dev, &parent->child_head, sibling_node)
dev_collect_stats(stats, dev);
}
void uclass_collect_stats(struct dm_stats *stats)
{
struct uclass *uc;
list_for_each_entry(uc, gd->uclass_root, sibling_node) {
int size;
stats->uc_count++;
stats->uc_size += sizeof(struct uclass);
size = uc->uc_drv->priv_auto;
if (size) {
stats->uc_attach_count++;
stats->uc_attach_size += size;
}
}
}
void dm_get_mem(struct dm_stats *stats)
{
memset(stats, '\0', sizeof(*stats));
dev_collect_stats(stats, gd->dm_root);
uclass_collect_stats(stats);
dev_tag_collect_stats(stats);
stats->total_size = stats->dev_size + stats->uc_size +
stats->attach_size_total + stats->uc_attach_size +
stats->tag_size;
}
#ifdef CONFIG_ACPIGEN
static int root_acpi_get_name(const struct udevice *dev, char *out_name)
{

View File

@@ -6,6 +6,7 @@
#include <malloc.h>
#include <asm/global_data.h>
#include <dm/root.h>
#include <dm/tag.h>
#include <linux/err.h>
#include <linux/list.h>
@@ -15,6 +16,24 @@ struct udevice;
DECLARE_GLOBAL_DATA_PTR;
static const char *const tag_name[] = {
[DM_TAG_PLAT] = "plat",
[DM_TAG_PARENT_PLAT] = "parent_plat",
[DM_TAG_UC_PLAT] = "uclass_plat",
[DM_TAG_PRIV] = "priv",
[DM_TAG_PARENT_PRIV] = "parent_priv",
[DM_TAG_UC_PRIV] = "uclass_priv",
[DM_TAG_DRIVER_DATA] = "driver_data",
[DM_TAG_EFI] = "efi",
};
const char *tag_get_name(enum dm_tag_t tag)
{
return tag_name[tag];
}
int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
{
struct dmtag_node *node;
@@ -137,3 +156,13 @@ int dev_tag_del_all(struct udevice *dev)
return -ENOENT;
}
void dev_tag_collect_stats(struct dm_stats *stats)
{
struct dmtag_node *node;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
stats->tag_count++;
stats->tag_size += sizeof(struct dmtag_node);
}
}