chiark / gitweb /
unit: reduce heap usage for unit objects
authorMichal Schmidt <mschmidt@redhat.com>
Sun, 15 Jan 2012 09:53:49 +0000 (10:53 +0100)
committerMichal Schmidt <mschmidt@redhat.com>
Mon, 16 Jan 2012 12:34:42 +0000 (13:34 +0100)
The storage of the unit objects on the heap is currently not very
efficient. For every unit object we allocate a chunk of memory as large
as the biggest unit type, although there are significant differences in
the units' real requirements.
pahole shows the following sizes of structs:
488  Target
496  Snapshot
512  Device
528  Path
560  Timer
576  Automount
1080 Socket
1160 Swap
1168 Service
1280 Mount

Usually there aren't many targets or snapshots in the system, but Device
is one of the most common unit types and for every one we waste
1280 - 512 = 768 bytes.

Fix it by allocating only the right amount for the given unit type.
On my machine (x86_64, with 39 LVM volumes) this decreases systemd's
USS (unique set size) by more than 300 KB.

13 files changed:
src/automount.c
src/device.c
src/manager.c
src/mount.c
src/path.c
src/service.c
src/snapshot.c
src/socket.c
src/swap.c
src/target.c
src/timer.c
src/unit.c
src/unit.h

index b70f8b4684ad64d82c1fabe6a346219d5ecf418d..c4191f6706e2adbbbbf91936520d022de8b7a0f8 100644 (file)
@@ -836,6 +836,7 @@ DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
 
 const UnitVTable automount_vtable = {
         .suffix = ".automount",
+        .object_size = sizeof(Automount),
         .sections =
                 "Unit\0"
                 "Automount\0"
index bffeca0d10c7a857bb4ae1212799ad8fbbacdc42..64665a8b87ae65580f5171a6426cd26b54cd9f36 100644 (file)
@@ -198,10 +198,12 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
         if (!u) {
                 delete = true;
 
-                if (!(u = unit_new(m)))
+                u = unit_new(m, sizeof(Device));
+                if (!u)
                         return -ENOMEM;
 
-                if ((r = device_add_escaped_name(u, path)) < 0)
+                r = device_add_escaped_name(u, path);
+                if (r < 0)
                         goto fail;
 
                 unit_add_to_load_queue(u);
@@ -583,6 +585,7 @@ DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
 
 const UnitVTable device_vtable = {
         .suffix = ".device",
+        .object_size = sizeof(Device),
         .sections =
                 "Unit\0"
                 "Device\0"
index a549209ca6481c13bf09e07dd27adb81f083a511..683197396f5eca3bc0291a36fd900c053854fd05 100644 (file)
@@ -1795,6 +1795,7 @@ unsigned manager_dispatch_load_queue(Manager *m) {
 
 int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
         Unit *ret;
+        UnitType t;
         int r;
 
         assert(m);
@@ -1811,24 +1812,30 @@ int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DB
         if (!name)
                 name = file_name_from_path(path);
 
-        if (!unit_name_is_valid(name, false)) {
+        t = unit_name_to_type(name);
+
+        if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid_no_type(name, false)) {
                 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
                 return -EINVAL;
         }
 
-        if ((ret = manager_get_unit(m, name))) {
+        ret = manager_get_unit(m, name);
+        if (ret) {
                 *_ret = ret;
                 return 1;
         }
 
-        if (!(ret = unit_new(m)))
+        ret = unit_new(m, unit_vtable[t]->object_size);
+        if (!ret)
                 return -ENOMEM;
 
-        if (path)
-                if (!(ret->meta.fragment_path = strdup(path))) {
+        if (path) {
+                ret->meta.fragment_path = strdup(path);
+                if (!ret->meta.fragment_path) {
                         unit_free(ret);
                         return -ENOMEM;
                 }
+        }
 
         if ((r = unit_add_name(ret, name)) < 0) {
                 unit_free(ret);
index 12c0710f1fb9d9cfd2de84957dd389946c79358c..f94c0eb278dbe10f12fc83d5c9563761f1d63438 100644 (file)
@@ -1395,13 +1395,16 @@ static int mount_add_one(
         if (!is_path(where))
                 return 0;
 
-        if (!(e = unit_name_from_path(where, ".mount")))
+        e = unit_name_from_path(where, ".mount");
+        if (!e)
                 return -ENOMEM;
 
-        if (!(u = manager_get_unit(m, e))) {
+        u = manager_get_unit(m, e);
+        if (!u) {
                 delete = true;
 
-                if (!(u = unit_new(m))) {
+                u = unit_new(m, sizeof(Mount));
+                if (!u) {
                         free(e);
                         return -ENOMEM;
                 }
@@ -1412,7 +1415,8 @@ static int mount_add_one(
                 if (r < 0)
                         goto fail;
 
-                if (!(MOUNT(u)->where = strdup(where))) {
+                MOUNT(u)->where = strdup(where);
+                if (!MOUNT(u)->where) {
                         r = -ENOMEM;
                         goto fail;
                 }
@@ -1837,6 +1841,7 @@ DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
 
 const UnitVTable mount_vtable = {
         .suffix = ".mount",
+        .object_size = sizeof(Mount),
         .sections =
                 "Unit\0"
                 "Mount\0"
index 957af05c7eb6651b361e491ad51cf396fc5d79cd..ae5052aeab6e009db34a1e6721958fc9254a2464 100644 (file)
@@ -717,6 +717,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
 
 const UnitVTable path_vtable = {
         .suffix = ".path",
+        .object_size = sizeof(Path),
         .sections =
                 "Unit\0"
                 "Path\0"
index 113be34ad0b3ccbcb4ca2870620d77991249d183..6ce6b19db9a2c0602b9274e4f28e935bd4bd9398 100644 (file)
@@ -3553,6 +3553,7 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
 
 const UnitVTable service_vtable = {
         .suffix = ".service",
+        .object_size = sizeof(Service),
         .sections =
                 "Unit\0"
                 "Service\0"
index 270dc4f2525f005b1c308ca40e5ac67904a03f0c..161629d9839a6b74608671a0345fe335053e8da8 100644 (file)
@@ -282,6 +282,7 @@ DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
 
 const UnitVTable snapshot_vtable = {
         .suffix = ".snapshot",
+        .object_size = sizeof(Snapshot),
 
         .no_alias = true,
         .no_instances = true,
index 7034436be06bb2454a7dadd282682dad5e2d9ef3..1a245aa872e8ac0421b9aefa801179b6e55606c5 100644 (file)
@@ -2114,6 +2114,7 @@ DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
 
 const UnitVTable socket_vtable = {
         .suffix = ".socket",
+        .object_size = sizeof(Socket),
         .sections =
                 "Unit\0"
                 "Socket\0"
index 4fa30a3e325f57e3be95692daa247de36dd9ef85..202c4e6625fb0e986693880c41bf8b888a178f64 100644 (file)
@@ -334,7 +334,8 @@ int swap_add_one(
         assert(m);
         assert(what);
 
-        if (!(e = unit_name_from_path(what, ".swap")))
+        e = unit_name_from_path(what, ".swap");
+        if (!e)
                 return -ENOMEM;
 
         u = manager_get_unit(m, e);
@@ -348,15 +349,18 @@ int swap_add_one(
         if (!u) {
                 delete = true;
 
-                if (!(u = unit_new(m))) {
+                u = unit_new(m, sizeof(Swap));
+                if (!u) {
                         free(e);
                         return -ENOMEM;
                 }
 
-                if ((r = unit_add_name(u, e)) < 0)
+                r = unit_add_name(u, e);
+                if (r < 0)
                         goto fail;
 
-                if (!(SWAP(u)->what = strdup(what))) {
+                SWAP(u)->what = strdup(what);
+                if (!SWAP(u)->what) {
                         r = -ENOMEM;
                         goto fail;
                 }
@@ -1341,6 +1345,7 @@ DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
 
 const UnitVTable swap_vtable = {
         .suffix = ".swap",
+        .object_size = sizeof(Swap),
         .sections =
                 "Unit\0"
                 "Swap\0"
index 340e9907f0d56084f77e7792c36b043234e0eb9e..b774cfbc3342adc60a33a63c534f54f8b986985d 100644 (file)
@@ -199,6 +199,7 @@ DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
 
 const UnitVTable target_vtable = {
         .suffix = ".target",
+        .object_size = sizeof(Target),
         .sections =
                 "Unit\0"
                 "Target\0"
index d127a117434a48a607d7d8d88dd6b0fb0e02fd29..87adb29e7ae61ae0e0f9c11c0c6397b9ffad5d7b 100644 (file)
@@ -468,6 +468,7 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
 
 const UnitVTable timer_vtable = {
         .suffix = ".timer",
+        .object_size = sizeof(Timer),
         .sections =
                 "Unit\0"
                 "Timer\0"
index 1fbfb1dea5fb7df643f04ed5d46b1abe1c171c77..fa3c2649b35b87cba48d1cf117021f0f7602fc34 100644 (file)
@@ -57,15 +57,18 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_PATH] = &path_vtable
 };
 
-Unit *unit_new(Manager *m) {
+Unit *unit_new(Manager *m, size_t size) {
         Unit *u;
 
         assert(m);
+        assert(size >= sizeof(Meta));
 
-        if (!(u = new0(Unit, 1)))
+        u = malloc0(size);
+        if (!u)
                 return NULL;
 
-        if (!(u->meta.names = set_new(string_hash_func, string_compare_func))) {
+        u->meta.names = set_new(string_hash_func, string_compare_func);
+        if (!u->meta.names) {
                 free(u);
                 return NULL;
         }
index 19314d6fbdde5c5f36dcddbc8b238454d1f69735..626bdc43af6b1a793a99d9f0c6011c93940cffa3 100644 (file)
@@ -286,6 +286,9 @@ union Unit {
 struct UnitVTable {
         const char *suffix;
 
+        /* How much memory does an object of this unit type need */
+        size_t object_size;
+
         /* Config file sections this unit type understands, separated
          * by NUL chars */
         const char *sections;
@@ -435,7 +438,7 @@ DEFINE_CAST(SNAPSHOT, Snapshot);
 DEFINE_CAST(SWAP, Swap);
 DEFINE_CAST(PATH, Path);
 
-Unit *unit_new(Manager *m);
+Unit *unit_new(Manager *m, size_t size);
 void unit_free(Unit *u);
 
 int unit_add_name(Unit *u, const char *name);