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

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