aboutsummaryrefslogtreecommitdiff
path: root/notes/deps_10k.txt
blob: 2e4a9269e37d84c076c43da2c2d76e2cb1b08d74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

10k dependencies problem
========================

How to efficiently load applications with an extreme number of 
dependencies? For example, an application with 10k dependencies.

This is of course an unlikely worst-case scenario, but I think it
makes sense to think about it. Especially given that I plan to add
class extenions / extension classes, which could lead to tiny "extension
modules" for various builtin types e.g. string, similar to how things
work in node.js.


Loader Service
--------------

Have a per-system "Loader Service" with the following API:

* (map_fd, entry, ctx) = map_file_refcounted(exec_fd, process-handle)


The Loader Service would keep all libraries that are needed in memory
(but packing several tiny libraries into each VM page).

The map API would provide access to:

* map_fd: all the mapped memory (shared for all processes)
* entry: an entry point offset (in the memory area) that can be called.
* ctx: a context object to pass to the entry point.

It could keep reference counts for all modules, so unused ones can be
de-allocated (but perhaps delay that until something else needs the memory
and/or there's a significant amount of memory pages that can be free'd).


Fast loading of files
---------------------

It would have to open 10k tiny files and copy all into memory!

Could io_uring speed things up?

Would keeping an fd to the library directory speed things up?

Would using a different directory than /usr/lib speed things up?
Does it need sub-directories? E.g. /usr/lib/.../slul-libs/a/aa/libaaa.so

Maybe execution can start before everything is loaded? Maybe userfaultfd
can be used for that?


Module format
-------------

The module format needs to be performance-optimized!

Use a compression format that is really fast to decompress, even on small
files. Perhaps LZ4 or zstd.

Use some really fast data structure for looking up dependencies.


Security
--------

The loader service should only be able to load from the system library
directory.

It should be sandboxed to ONLY have access to this directory, and only
read-only access. And of course to the unix socket (but maybe that can
be provided by systemd?)

It should only have access to the minimum amount of syscalls needed.

It does not need to have any other access to the system (devices, etc).


OS performance
--------------

With a SSD, not sure about exact specs:

    time head /usr/lib/x86_64-linux-gnu/*.so.{0,1,2} > /dev/null 2>&1
    real    0.327s
    user    0.009s
    sys     0.059s

    ls -1 /usr/lib/x86_64-linux-gnu/*.so.{0,1,2} | wc -l
    762

0.327/762*10e3 = 4.3 seconds
(assuming the workload was / would be I/O bound in both cases)

Running it a second time (with hot caches) gave:

    time head /usr/lib/x86_64-linux-gnu/*.so.{0,1,2} > /dev/null 2>&1
    real    0.018s
    user    0.009s
    sys     0.009s


Alternative solution
====================

Could have an post-installation task that rebuilds some "mega-package-file"
that contains every libraries that is installed. That file could then be
mapped into memory when an application is loaded.

However, there are some downsides:

* The large amount of mapped pages could possibly cause various slowness
  and/or use lots of kernel memory. Actually, I don't know what would happen
  and I guess it is OS specific.
* It could use quite a bit of virtual address space, which could be
  a problem on 32-bit platforms.