OILS / cpp / obj_layout_test.cc View on Github | oilshell.org

188 lines, 92 significant
1#include "_gen/core/runtime.asdl.h" // Cell, etc
2#include "_gen/frontend/syntax.asdl.h"
3#include "vendor/greatest.h"
4
5TEST sizeof_syntax() {
6 // 40 bytes (after merging with line_span January 2023)
7 // - Get rid of 'string val'
8 // - Replace 'int line_id' with SourceLine
9 // - Maybe recompute length on demand
10 log("sizeof(Token) = %d", sizeof(syntax_asdl::Token));
11 log("alignof(Token) = %d", alignof(syntax_asdl::Token));
12 log("alignof(Token*) = %d", alignof(syntax_asdl::Token *));
13
14 // Reordered to be 16 bytes
15 log("sizeof(runtime_asdl::Cell) = %d", sizeof(runtime_asdl::Cell));
16
17 // 24 bytes: std::vector
18 log("sizeof(List<int>) = %d", sizeof(List<int>));
19 log("sizeof(List<BigStr*>) = %d", sizeof(List<BigStr *>));
20
21 log("sizeof(Slab<int>) = %d", sizeof(Slab<int>));
22 log("sizeof(Slab<BigStr*>) = %d", sizeof(Slab<BigStr *>));
23 // Right after object header
24 log("kSlabHeaderSize = %d", kSlabHeaderSize);
25
26 // Unlike Python, this is -1, not 255!
27 int mod = -1 % 256;
28 log("mod = %d", mod);
29
30 log("alignof(bool) = %d", alignof(bool));
31 log("alignof(int) = %d", alignof(int));
32 log("alignof(float) = %d", alignof(float));
33
34 log("sizeof(BigStr) = %d", sizeof(BigStr));
35 log("alignof(BigStr) = %d", alignof(BigStr));
36
37 log("sizeof(BigStr*) = %d", sizeof(BigStr *));
38 log("alignof(BigStr*) = %d", alignof(BigStr *));
39
40 log("alignof(max_align_t) = %d", alignof(max_align_t));
41
42 PASS();
43}
44
45// Doesn't really test anything
46TEST sizeof_core_types() {
47 log("");
48
49 // 8 byte header
50 log("sizeof(ObjHeader) = %d", sizeof(ObjHeader));
51 // 8 + 128 possible entries
52 // log("sizeof(LayoutFixed) = %d", sizeof(LayoutFixed));
53
54 // 24 = 4 + (4 + 4 + 4) + 8
55 // Feels like a small string optimization here would be nice.
56 log("sizeof(BigStr) = %d", sizeof(BigStr));
57 // 16 = 4 + pad4 + 8
58 log("sizeof(List) = %d", sizeof(List<int>));
59 // 32 = 4 + pad4 + 8 + 8 + 8
60 log("sizeof(Dict) = %d", sizeof(Dict<int, int>));
61
62#ifndef MARK_SWEEP
63 int min_obj_size = sizeof(LayoutForwarded);
64 int short_str_size = aligned(kStrHeaderSize + 1);
65
66 log("kStrHeaderSize = %d", kStrHeaderSize);
67 log("aligned(kStrHeaderSize + 1) = %d", short_str_size);
68 log("sizeof(LayoutForwarded) = %d", min_obj_size);
69
70 ASSERT(min_obj_size <= short_str_size);
71#endif
72
73#if 0
74 char* p = static_cast<char*>(gHeap.Allocate(17));
75 char* q = static_cast<char*>(gHeap.Allocate(9));
76 log("p = %p", p);
77 log("q = %p", q);
78#endif
79
80 // BigStr = 16 and List = 24.
81 // Rejected ideas about slicing:
82 //
83 // - Use data[len] == '\0' as OWNING and data[len] != '\0' as a slice?
84 // It doesn't work because s[1:] would always have that problem
85 //
86 // - s->data == (void*)(s + 1)
87 // Owning string has the data RIGHT AFTER?
88 // Maybe works? but probably a bad idea because of GLOBAL BigStr instances.
89
90 log("");
91 log("sizeof(BigStr) = %zu", sizeof(BigStr));
92 log("sizeof(List<int>) = %zu", sizeof(List<int>));
93 log("sizeof(Dict<int, BigStr*>) = %zu", sizeof(Dict<int, BigStr *>));
94 log("sizeof(Tuple2<int, int>) = %zu", sizeof(Tuple2<int, int>));
95 log("sizeof(Tuple2<BigStr*, BigStr*>) = %zu",
96 sizeof(Tuple2<BigStr *, BigStr *>));
97 log("sizeof(Tuple3<int, int, int>) = %zu", sizeof(Tuple3<int, int, int>));
98
99 PASS();
100}
101
102TEST slab_growth() {
103 // TODO: All slabs should start out at 32
104
105 auto li = Alloc<List<int>>();
106 log("li->items_ %p", li->slab_);
107
108 // At some point it moves
109 for (int i = 0; i < 20; ++i) {
110 li->append(42);
111 int size = 8 + (sizeof(int) * li->capacity_);
112 log("%2d. cap %2d, size %3d, li->slab_ %p", i, li->capacity_, size,
113 li->slab_);
114 }
115
116 log("---");
117
118 auto lp = Alloc<List<BigStr *>>();
119 log("lp->items_ %p", lp->slab_);
120
121 // At some point it moves
122 for (int i = 0; i < 20; ++i) {
123 lp->append(kEmptyString);
124 int size = 8 + (sizeof(BigStr *) * lp->capacity_);
125 log("%2d. cap %2d, size %3d, lp->slab_ %p", i, lp->capacity_, size,
126 lp->slab_);
127 }
128
129 PASS();
130}
131
132TEST malloc_address_test() {
133 // glibc gives us blocks of 32 bytes!
134 // 1. diff = -240
135 // 2. diff = 94064
136 // 3. diff = 32
137 // 4. diff = 32
138 // 5. diff = 32
139
140 // tcmalloc has tighter packing!
141 // 1. diff = -8
142 // 2. diff = 32
143 // 3. diff = 8
144 // 4. diff = 8
145 // 5. diff = 8
146
147 // 2023-08: If I pass 4096, I get 4112, so 16 byte diff
148 // 2023-08: If I pass 4080, I get 4096
149
150 // int alloc_size = 24 * 682; // 16368 is close to 16384 - 16 bytes again
151 int alloc_size = 48 * 341; // heap 2 is the same size
152
153 // int alloc_size = 4080;
154 // int alloc_size = 1;
155
156 char *p[20];
157 for (int i = 0; i < 20; ++i) {
158 p[i] = static_cast<char *>(malloc(alloc_size));
159 if (i != 0) {
160 char *prev = p[i - 1];
161 log("%2d. diff = %d", i, p[i] - prev);
162 }
163 }
164
165 for (int i = 0; i < 20; ++i) {
166 free(p[i]);
167 }
168
169 PASS();
170}
171
172GREATEST_MAIN_DEFS();
173
174int main(int argc, char **argv) {
175 gHeap.Init();
176
177 GREATEST_MAIN_BEGIN();
178
179 RUN_TEST(sizeof_syntax);
180 RUN_TEST(sizeof_core_types);
181 RUN_TEST(slab_growth);
182 RUN_TEST(malloc_address_test);
183
184 gHeap.CleanProcessExit();
185
186 GREATEST_MAIN_END();
187 return 0;
188}