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