dm: core: Allow getting some basic stats
authorSimon Glass <sjg@chromium.org>
Fri, 17 Dec 2021 03:59:32 +0000 (20:59 -0700)
committerTom Rini <trini@konsulko.com>
Thu, 23 Dec 2021 15:24:40 +0000 (10:24 -0500)
Add a function that returns some basic stats about driver model. For now
we only have two.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/core/device.c
drivers/core/root.c
drivers/core/uclass.c
include/dm/device.h
include/dm/root.h
include/dm/uclass-internal.h
test/dm/core.c

index 74374ff..4873c47 100644 (file)
@@ -739,6 +739,17 @@ int device_get_child_count(const struct udevice *parent)
        return count;
 }
 
+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)
+               count += device_get_decendent_count(dev);
+
+       return count;
+}
+
 int device_find_child_by_seq(const struct udevice *parent, int seq,
                             struct udevice **devp)
 {
index 26b8195..815173f 100644 (file)
@@ -26,6 +26,7 @@
 #include <dm/read.h>
 #include <dm/root.h>
 #include <dm/uclass.h>
+#include <dm/uclass-internal.h>
 #include <dm/util.h>
 #include <linux/list.h>
 
@@ -407,6 +408,12 @@ int dm_init_and_scan(bool pre_reloc_only)
        return 0;
 }
 
+void dm_get_stats(int *device_countp, int *uclass_countp)
+{
+       *device_countp = device_get_decendent_count(gd->dm_root);
+       *uclass_countp = uclass_get_count();
+}
+
 #ifdef CONFIG_ACPIGEN
 static int root_acpi_get_name(const struct udevice *dev, char *out_name)
 {
index 2aa2143..336ea8d 100644 (file)
@@ -643,6 +643,19 @@ int uclass_next_device_check(struct udevice **devp)
        return device_probe(*devp);
 }
 
+int uclass_get_count(void)
+{
+       const struct uclass *uc;
+       int count = 0;
+
+       if (gd->dm_root) {
+               list_for_each_entry(uc, gd->uclass_root, sibling_node)
+                       count++;
+       }
+
+       return count;
+}
+
 int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
                                struct udevice **devp)
 {
index 544734e..cf785f7 100644 (file)
@@ -593,7 +593,7 @@ int device_get_child(const struct udevice *parent, int index,
                     struct udevice **devp);
 
 /**
- * device_get_child_count() - Get the available child count of a device
+ * device_get_child_count() - Get the child count of a device
  *
  * Returns the number of children to a device.
  *
@@ -602,6 +602,15 @@ int device_get_child(const struct udevice *parent, int index,
 int device_get_child_count(const struct udevice *parent);
 
 /**
+ * device_get_decendent_count() - Get the total number of decendents of a device
+ *
+ * Returns the total number of decendents, including all children
+ *
+ * @parent:    Parent device to check
+ */
+int device_get_decendent_count(const struct udevice *parent);
+
+/**
  * device_find_child_by_seq() - Find a child device based on a sequence
  *
  * This searches for a device with the given seq.
index 42510b1..780f269 100644 (file)
@@ -131,4 +131,12 @@ int dm_remove_devices_flags(uint flags);
 static inline int dm_remove_devices_flags(uint flags) { return 0; }
 #endif
 
+/**
+ * dm_get_stats() - Get some stats for driver mode
+ *
+ * @device_countp: Returns total number of devices that are bound
+ * @uclass_countp: Returns total number of uclasses in use
+ */
+void dm_get_stats(int *device_countp, int *uclass_countp);
+
 #endif
index 49808c5..fb0edcc 100644 (file)
@@ -307,6 +307,13 @@ static inline int uclass_pre_remove_device(struct udevice *dev) { return 0; }
 #endif
 
 /**
+ * uclass_get_count() - Get the number of uclasses
+ *
+ * Returns the number of uclasses instantiated in driver model
+ */
+int uclass_get_count(void);
+
+/**
  * uclass_find() - Find uclass by its id
  *
  * @id:                Id to serach for
index c9a7606..c76dfdb 100644 (file)
@@ -307,11 +307,15 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
 {
        int op_count[DM_TEST_OP_COUNT];
        struct udevice *dev, *test_dev;
+       int start_dev_count, start_uc_count;
+       int dev_count, uc_count;
        int pingret;
        int ret;
 
        memcpy(op_count, dm_testdrv_op_count, sizeof(op_count));
 
+       dm_get_stats(&start_dev_count, &start_uc_count);
+
        ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
                                        &dev));
        ut_assert(dev);
@@ -319,6 +323,11 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
                        == op_count[DM_TEST_OP_BIND] + 1);
        ut_assert(!dev_get_priv(dev));
 
+       /* We should have one more device */
+       dm_get_stats(&dev_count, &uc_count);
+       ut_asserteq(start_dev_count + 1, dev_count);
+       ut_asserteq(start_uc_count, uc_count);
+
        /* Probe the device - it should fail allocating private data */
        uts->force_fail_alloc = 1;
        ret = device_probe(dev);
@@ -353,6 +362,11 @@ static int dm_test_lifecycle(struct unit_test_state *uts)
        ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]);
        ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]);
 
+       /* We should have one less device */
+       dm_get_stats(&dev_count, &uc_count);
+       ut_asserteq(start_dev_count, dev_count);
+       ut_asserteq(start_uc_count, uc_count);
+
        return 0;
 }
 DM_TEST(dm_test_lifecycle, UT_TESTF_SCAN_PDATA | UT_TESTF_PROBE_TEST);
@@ -526,17 +540,31 @@ DM_TEST(dm_test_leak, 0);
 /* Test uclass init/destroy methods */
 static int dm_test_uclass(struct unit_test_state *uts)
 {
+       int dev_count, uc_count;
        struct uclass *uc;
 
+       /* We should have just the root device and uclass */
+       dm_get_stats(&dev_count, &uc_count);
+       ut_asserteq(1, dev_count);
+       ut_asserteq(1, uc_count);
+
        ut_assertok(uclass_get(UCLASS_TEST, &uc));
        ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]);
        ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_DESTROY]);
        ut_assert(uclass_get_priv(uc));
 
+       dm_get_stats(&dev_count, &uc_count);
+       ut_asserteq(1, dev_count);
+       ut_asserteq(2, uc_count);
+
        ut_assertok(uclass_destroy(uc));
        ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]);
        ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_DESTROY]);
 
+       dm_get_stats(&dev_count, &uc_count);
+       ut_asserteq(1, dev_count);
+       ut_asserteq(1, uc_count);
+
        return 0;
 }
 DM_TEST(dm_test_uclass, 0);
@@ -1217,3 +1245,16 @@ static int dm_test_dma_offset(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_dma_offset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
 #endif
+
+/* Test dm_get_stats() */
+static int dm_test_get_stats(struct unit_test_state *uts)
+{
+       int dev_count, uc_count;
+
+       dm_get_stats(&dev_count, &uc_count);
+       ut_assert(dev_count > 50);
+       ut_assert(uc_count > 30);
+
+       return 0;
+}
+DM_TEST(dm_test_get_stats, UT_TESTF_SCAN_FDT);