diff --git a/Makefile b/Makefile index cd118c4..d2ce20b 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,17 @@ COV_TGT := $(BUILD_DIR)/coverage.xml CC = $(MAKE_CC) CFLAGS += -g -I$(INC_DIR) -O -Wall -pedantic -std=c99 + +# Check whether valgrind is available. +ifeq ($(shell command -v valgrind),) +# If not, we probably shouldn't try to include , +# which we use to instrument our memory allocator. +# +# NOTE: this is just a heuristic that may not be very reliable. +# We should probably implement better dependency management. +CFLAGS += -DNVALGRIND +endif + TEST_CFLAGS = $(CFLAGS) -g -DSSM_DEBUG --coverage LD = $(MAKE_LD) diff --git a/examples/ssm-examples.h b/examples/ssm-examples.h index 1e67b07..a0552d1 100644 --- a/examples/ssm-examples.h +++ b/examples/ssm-examples.h @@ -49,7 +49,7 @@ void ssm_throw(enum ssm_error reason, const char *file, int line, } #define MAX_PAGES 2048 -static void *pages[MAX_PAGES]; +static uint8_t *pages[SSM_MEM_PAGE_SIZE][MAX_PAGES]; static size_t allocated_pages = 0; static void *alloc_page(void) { @@ -57,7 +57,7 @@ static void *alloc_page(void) { SSM_THROW(SSM_EXHAUSTED_MEMORY); exit(3); } - void *m = pages[allocated_pages++] = malloc(SSM_MEM_PAGE_SIZE); + void *m = pages[allocated_pages++]; memset(m, 0, SSM_MEM_PAGE_SIZE); return m; } @@ -66,6 +66,8 @@ static void *alloc_mem(size_t size) { return malloc(size); } static void free_mem(void *mem, size_t size) { free(mem); } +static void free_page(void *mem) { allocated_pages--; } + static void print_help(char *prog) { printf("Usage: %s [OPTION]... [--] [ARG]...\n", prog); printf("\n"); @@ -84,8 +86,6 @@ static void print_help(char *prog) { char **ssm_init_args; int main(int argc, char *argv[]) { - ssm_mem_init(alloc_page, alloc_mem, free_mem); - size_t stop_at_s = 20; char *prog = *argv; @@ -118,8 +118,11 @@ int main(int argc, char *argv[]) { } ssm_init_args = argv; - ssm_time_t stop_at = stop_at_s == 0 ? SSM_NEVER : stop_at_s * SSM_SECOND; + printf("%s: simulating up to %lu seconds\n", prog, + (unsigned long)stop_at / SSM_SECOND); + + ssm_mem_init(alloc_page, alloc_mem, free_mem); ssm_program_init(); @@ -133,8 +136,7 @@ int main(int argc, char *argv[]) { ssm_program_exit(); - for (size_t p = 0; p < allocated_pages; p++) - free(pages[p]); + ssm_mem_destroy(free_page); return 0; } diff --git a/include/ssm-internal.h b/include/ssm-internal.h index 4598c27..fd54ce9 100644 --- a/include/ssm-internal.h +++ b/include/ssm-internal.h @@ -154,16 +154,36 @@ enum ssm_kind { * alloc_mem_handler. These handlers may also assume they will not be invoked * to request memory ranges of less than #SSM_MEM_POOL_MAX bytes. * + * If the allocator is compiled with valgrind support (i.e., without defining + * @a NVALGRIND), it will perform a leak-check summary, to checkpoint how much + * memory has already been allocated. + * * @platformonly * - * @param alloc_page_handler allocates pages. - * @param alloc_mem_handler allocates arbitrarily large. - * @param free_mem_handler frees pages allocated with @a alloc_mem_handler. + * @param alloc_page_handler allocates pages. + * @param alloc_mem_handler allocates arbitrarily large. + * @param free_mem_handler frees memory allocated with @a alloc_mem_handler. */ void ssm_mem_init(void *(*alloc_page_handler)(void), void *(*alloc_mem_handler)(size_t), void (*free_mem_handler)(void *, size_t)); +/** @brief Tears down the underlying allocator system. + * + * If the allocator is compiled with valgrind support (i.e., without defining + * @a NVALGRIND), it will perform a full leak-check summary, to report how much + * memory has been leaked since ssm_mem_init(). + * + * @TODO this doesn't actually call @a free_page_handler yet. It still needs to + * be implemented, perhaps with the help of a superblock header to keep + * track of all pages allocated for each mempool + * + * @platformonly + * + * @param free_page_handler frees pages allocated with @a alloc_page_handler. + */ +void ssm_mem_destroy(void (*free_page_handler)(void *)); + #ifndef SSM_MEM_POOL_MIN /** @brief Block size of the smallest memory pool. * @@ -232,4 +252,8 @@ void ssm_mem_init(void *(*alloc_page_handler)(void), /** @} */ +#ifndef NVALGRIND +#include +#endif + #endif /* _SSM_SCHED_H */ diff --git a/runtests.sh b/runtests.sh index 6a2b502..774b1b1 100755 --- a/runtests.sh +++ b/runtests.sh @@ -15,6 +15,7 @@ set -euf set -o pipefail BUILD_DIR=./build +declare -a VG_FLAGS=("--leak-check=full" "--show-leak-kinds=all") scriptname="$(basename "$0")" @@ -26,6 +27,7 @@ run () { local exe="$BUILD_DIR/$1" shift echo "$exe" "$@" + echo "$exe" "$@" >&2 set +e "$exe" "$@" 2>&1 | sed 's/^/# /' local exit_code="$?" @@ -39,9 +41,10 @@ run () { vg () { local exe="$BUILD_DIR/$1" shift - echo "$exe" "$@" + echo valgrind "${VG_FLAGS[@]}" "$exe" "$@" + echo valgrind "${VG_FLAGS[@]}" "$exe" "$@" >&2 set +e - valgrind "$exe" "$@" 2>&1 | sed 's/^/# /' + valgrind "${VG_FLAGS[@]}" "$exe" "$@" 2>&1 | sed 's/^/# /' local exit_code="$?" set -e if [ "$exit_code" -ne 0 ]; then @@ -94,7 +97,7 @@ else fi make clean -CFLAGS=-DSSM_DEBUG_NO_ALLOC make exes tests +make exes tests if command -v valgrind >/dev/null ; then rm -f build/examples.vg-out diff --git a/src/ssm-mem.c b/src/ssm-mem.c index 8563bb4..d6a2abc 100644 --- a/src/ssm-mem.c +++ b/src/ssm-mem.c @@ -78,6 +78,13 @@ static inline size_t find_pool_size(size_t size) { return SSM_MEM_POOL_COUNT; } +static inline block_t *find_next_block(block_t *block, size_t pool_size) { + if (block->free_list_next == UNINITIALIZED_FREE_BLOCK) + return block + pool_size / sizeof(block_t); + else + return block->free_list_next; +} + /** @brief Allocate a new block for a memory pool. * * Calls alloc_page() to allocate a new zero-initialized page for the memory @@ -91,11 +98,18 @@ static inline size_t find_pool_size(size_t size) { static inline void alloc_pool(size_t p) { block_t *new_page = alloc_page(); SSM_ASSERT(END_OF_FREELIST < new_page); - struct mem_pool *pool = &mem_pools[p]; size_t last_block = BLOCKS_PER_PAGE - SSM_MEM_POOL_SIZE(p) / sizeof(block_t); new_page[last_block].free_list_next = pool->free_list_head; pool->free_list_head = new_page; + +#ifndef NVALGRIND + // Mark as NOACCESS; nothing should touch this memory until it is allocated. + VALGRIND_MAKE_MEM_NOACCESS(new_page, SSM_MEM_PAGE_SIZE); + + // Label this page with a human-readable name, for memory error reporting. + VALGRIND_CREATE_BLOCK(new_page, SSM_MEM_PAGE_SIZE, "SSM memory pool page"); +#endif } void ssm_mem_init(void *(*alloc_page_handler)(void), @@ -105,8 +119,34 @@ void ssm_mem_init(void *(*alloc_page_handler)(void), alloc_mem = alloc_mem_handler; free_mem = free_mem_handler; - for (size_t p = 0; p < SSM_MEM_POOL_COUNT; p++) + for (size_t p = 0; p < SSM_MEM_POOL_COUNT; p++) { mem_pools[p].free_list_head = END_OF_FREELIST; + } + +#ifndef NVALGRIND + // Ask Valgrind to checkpoint the amount of memory allocated so far. + VALGRIND_PRINTF("Performing leak check at memory initialization.\n"); + VALGRIND_PRINTF("(Checkpoints how much memory is allocated at init time.)\n"); + VALGRIND_PRINTF("\n"); + VALGRIND_DO_QUICK_LEAK_CHECK; +#endif +} + +void ssm_mem_destroy(void (*free_page_handler)(void *)) { + // TODO: call free_page_handler on all superblocks in each mem pool. + // for (size_t p = 0; p < SSM_MEM_POOL_COUNT; p++) { + // if (mem_pools[p].free_list_head != END_OF_FREELIST) { + // } + // } + +#ifndef NVALGRIND + // Report how much memory has been leaked since the checkpoint in + // ssm_mem_init(). + VALGRIND_PRINTF("About to destroy SSM allocator. Performing leak check.\n"); + VALGRIND_PRINTF("(Note that leaks from malloc() may be false positives.)\n"); + VALGRIND_PRINTF("\n"); + VALGRIND_DO_ADDED_LEAK_CHECK; +#endif } void ssm_mem_prealloc(size_t size, size_t num_pages) { @@ -118,9 +158,6 @@ void ssm_mem_prealloc(size_t size, size_t num_pages) { } void *ssm_mem_alloc(size_t size) { -#ifdef SSM_DEBUG_NO_ALLOC - return alloc_mem(size); -#else size_t p = find_pool_size(size); if (p >= SSM_MEM_POOL_COUNT) return alloc_mem(size); @@ -130,30 +167,43 @@ void *ssm_mem_alloc(size_t size) { if (pool->free_list_head == END_OF_FREELIST) alloc_pool(p); - void *buf = pool->free_list_head->block_buf; + void *m = pool->free_list_head->block_buf; - if (pool->free_list_head->free_list_next == UNINITIALIZED_FREE_BLOCK) - pool->free_list_head += SSM_MEM_POOL_SIZE(p) / sizeof(block_t); - else - pool->free_list_head = pool->free_list_head->free_list_next; +#ifndef NVALGRIND + // Tell Valgrind that we have allocated m as a chunk of pool. + // + // The memory range [m..m+size] is now considered DEFINED. + VALGRIND_MALLOCLIKE_BLOCK(m, size, 0, 1); +#endif + + pool->free_list_head = + find_next_block(pool->free_list_head, SSM_MEM_POOL_SIZE(p)); - return buf; +#ifndef NVALGRIND + // Make the memory range [m..m+size] undefined, because the caller should + // not rely on allocated chunks being defined. + VALGRIND_MAKE_MEM_UNDEFINED(m, size); #endif + + return m; } void ssm_mem_free(void *m, size_t size) { -#ifdef SSM_DEBUG_NO_ALLOC - free_mem(m, size); -#else - size_t pool = find_pool_size(size); - if (pool >= SSM_MEM_POOL_COUNT) { + size_t p = find_pool_size(size); + if (p >= SSM_MEM_POOL_COUNT) { free_mem(m, size); return; } + struct mem_pool *pool = &mem_pools[p]; + block_t *new_head = m; - new_head->free_list_next = mem_pools[pool].free_list_head; - mem_pools[pool].free_list_head = new_head; + new_head->free_list_next = pool->free_list_head; + pool->free_list_head = new_head; + +#ifndef NVALGRIND + // Tell Valgrind that we have freed m. + VALGRIND_FREELIKE_BLOCK(m, 0); #endif } diff --git a/test/examples.out b/test/examples.out index 72f7c85..8fd8bec 100644 --- a/test/examples.out +++ b/test/examples.out @@ -1,22 +1,29 @@ ./build/fib +# ./build/fib: simulating up to 20 seconds # ./build/fib: simulated 3 seconds # 3 ./build/fib 4 +# ./build/fib: simulating up to 20 seconds # ./build/fib: simulated 4 seconds # 5 ./build/fib 5 +# ./build/fib: simulating up to 20 seconds # ./build/fib: simulated 5 seconds # 8 ./build/fib 13 +# ./build/fib: simulating up to 20 seconds # ./build/fib: simulated 13 seconds # 377 ./build/fib 15 +# ./build/fib: simulating up to 20 seconds # ./build/fib: simulated 15 seconds # 987 ./build/onetwo +# ./build/onetwo: simulating up to 20 seconds # a = 22 # ./build/onetwo: simulated 0 seconds ./build/clock +# ./build/clock: simulating up to 20 seconds # 1 # 2 # 3 @@ -39,6 +46,7 @@ # 20 # ./build/clock: simulated 20 seconds ./build/counter +# ./build/counter: simulating up to 20 seconds # clk = 0 # q1 = 0 d1 = 0 # q2 = 0 d2 = 0 @@ -74,10 +82,12 @@ # q2 = 5 d2 = 6 # ./build/counter: simulated 20 seconds ./build/list +# ./build/list: simulating up to 20 seconds # 1::2::3::[] # 2::3::4::[] # ./build/list: simulated 0 seconds ./build/list 2048 +# ./build/list: simulating up to 20 seconds # 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::116::117::118::119::120::121::122::123::124::125::126::127::128::129::130::131::132::133::134::135::136::137::138::139::140::141::142::143::144::145::146::147::148::149::150::151::152::153::154::155::156::157::158::159::160::161::162::163::164::165::166::167::168::169::170::171::172::173::174::175::176::177::178::179::180::181::182::183::184::185::186::187::188::189::190::191::192::193::194::195::196::197::198::199::200::201::202::203::204::205::206::207::208::209::210::211::212::213::214::215::216::217::218::219::220::221::222::223::224::225::226::227::228::229::230::231::232::233::234::235::236::237::238::239::240::241::242::243::244::245::246::247::248::249::250::251::252::253::254::255::256::257::258::259::260::261::262::263::264::265::266::267::268::269::270::271::272::273::274::275::276::277::278::279::280::281::282::283::284::285::286::287::288::289::290::291::292::293::294::295::296::297::298::299::300::301::302::303::304::305::306::307::308::309::310::311::312::313::314::315::316::317::318::319::320::321::322::323::324::325::326::327::328::329::330::331::332::333::334::335::336::337::338::339::340::341::342::343::344::345::346::347::348::349::350::351::352::353::354::355::356::357::358::359::360::361::362::363::364::365::366::367::368::369::370::371::372::373::374::375::376::377::378::379::380::381::382::383::384::385::386::387::388::389::390::391::392::393::394::395::396::397::398::399::400::401::402::403::404::405::406::407::408::409::410::411::412::413::414::415::416::417::418::419::420::421::422::423::424::425::426::427::428::429::430::431::432::433::434::435::436::437::438::439::440::441::442::443::444::445::446::447::448::449::450::451::452::453::454::455::456::457::458::459::460::461::462::463::464::465::466::467::468::469::470::471::472::473::474::475::476::477::478::479::480::481::482::483::484::485::486::487::488::489::490::491::492::493::494::495::496::497::498::499::500::501::502::503::504::505::506::507::508::509::510::511::512::513::514::515::516::517::518::519::520::521::522::523::524::525::526::527::528::529::530::531::532::533::534::535::536::537::538::539::540::541::542::543::544::545::546::547::548::549::550::551::552::553::554::555::556::557::558::559::560::561::562::563::564::565::566::567::568::569::570::571::572::573::574::575::576::577::578::579::580::581::582::583::584::585::586::587::588::589::590::591::592::593::594::595::596::597::598::599::600::601::602::603::604::605::606::607::608::609::610::611::612::613::614::615::616::617::618::619::620::621::622::623::624::625::626::627::628::629::630::631::632::633::634::635::636::637::638::639::640::641::642::643::644::645::646::647::648::649::650::651::652::653::654::655::656::657::658::659::660::661::662::663::664::665::666::667::668::669::670::671::672::673::674::675::676::677::678::679::680::681::682::683::684::685::686::687::688::689::690::691::692::693::694::695::696::697::698::699::700::701::702::703::704::705::706::707::708::709::710::711::712::713::714::715::716::717::718::719::720::721::722::723::724::725::726::727::728::729::730::731::732::733::734::735::736::737::738::739::740::741::742::743::744::745::746::747::748::749::750::751::752::753::754::755::756::757::758::759::760::761::762::763::764::765::766::767::768::769::770::771::772::773::774::775::776::777::778::779::780::781::782::783::784::785::786::787::788::789::790::791::792::793::794::795::796::797::798::799::800::801::802::803::804::805::806::807::808::809::810::811::812::813::814::815::816::817::818::819::820::821::822::823::824::825::826::827::828::829::830::831::832::833::834::835::836::837::838::839::840::841::842::843::844::845::846::847::848::849::850::851::852::853::854::855::856::857::858::859::860::861::862::863::864::865::866::867::868::869::870::871::872::873::874::875::876::877::878::879::880::881::882::883::884::885::886::887::888::889::890::891::892::893::894::895::896::897::898::899::900::901::902::903::904::905::906::907::908::909::910::911::912::913::914::915::916::917::918::919::920::921::922::923::924::925::926::927::928::929::930::931::932::933::934::935::936::937::938::939::940::941::942::943::944::945::946::947::948::949::950::951::952::953::954::955::956::957::958::959::960::961::962::963::964::965::966::967::968::969::970::971::972::973::974::975::976::977::978::979::980::981::982::983::984::985::986::987::988::989::990::991::992::993::994::995::996::997::998::999::1000::1001::1002::1003::1004::1005::1006::1007::1008::1009::1010::1011::1012::1013::1014::1015::1016::1017::1018::1019::1020::1021::1022::1023::1024::1025::1026::1027::1028::1029::1030::1031::1032::1033::1034::1035::1036::1037::1038::1039::1040::1041::1042::1043::1044::1045::1046::1047::1048::1049::1050::1051::1052::1053::1054::1055::1056::1057::1058::1059::1060::1061::1062::1063::1064::1065::1066::1067::1068::1069::1070::1071::1072::1073::1074::1075::1076::1077::1078::1079::1080::1081::1082::1083::1084::1085::1086::1087::1088::1089::1090::1091::1092::1093::1094::1095::1096::1097::1098::1099::1100::1101::1102::1103::1104::1105::1106::1107::1108::1109::1110::1111::1112::1113::1114::1115::1116::1117::1118::1119::1120::1121::1122::1123::1124::1125::1126::1127::1128::1129::1130::1131::1132::1133::1134::1135::1136::1137::1138::1139::1140::1141::1142::1143::1144::1145::1146::1147::1148::1149::1150::1151::1152::1153::1154::1155::1156::1157::1158::1159::1160::1161::1162::1163::1164::1165::1166::1167::1168::1169::1170::1171::1172::1173::1174::1175::1176::1177::1178::1179::1180::1181::1182::1183::1184::1185::1186::1187::1188::1189::1190::1191::1192::1193::1194::1195::1196::1197::1198::1199::1200::1201::1202::1203::1204::1205::1206::1207::1208::1209::1210::1211::1212::1213::1214::1215::1216::1217::1218::1219::1220::1221::1222::1223::1224::1225::1226::1227::1228::1229::1230::1231::1232::1233::1234::1235::1236::1237::1238::1239::1240::1241::1242::1243::1244::1245::1246::1247::1248::1249::1250::1251::1252::1253::1254::1255::1256::1257::1258::1259::1260::1261::1262::1263::1264::1265::1266::1267::1268::1269::1270::1271::1272::1273::1274::1275::1276::1277::1278::1279::1280::1281::1282::1283::1284::1285::1286::1287::1288::1289::1290::1291::1292::1293::1294::1295::1296::1297::1298::1299::1300::1301::1302::1303::1304::1305::1306::1307::1308::1309::1310::1311::1312::1313::1314::1315::1316::1317::1318::1319::1320::1321::1322::1323::1324::1325::1326::1327::1328::1329::1330::1331::1332::1333::1334::1335::1336::1337::1338::1339::1340::1341::1342::1343::1344::1345::1346::1347::1348::1349::1350::1351::1352::1353::1354::1355::1356::1357::1358::1359::1360::1361::1362::1363::1364::1365::1366::1367::1368::1369::1370::1371::1372::1373::1374::1375::1376::1377::1378::1379::1380::1381::1382::1383::1384::1385::1386::1387::1388::1389::1390::1391::1392::1393::1394::1395::1396::1397::1398::1399::1400::1401::1402::1403::1404::1405::1406::1407::1408::1409::1410::1411::1412::1413::1414::1415::1416::1417::1418::1419::1420::1421::1422::1423::1424::1425::1426::1427::1428::1429::1430::1431::1432::1433::1434::1435::1436::1437::1438::1439::1440::1441::1442::1443::1444::1445::1446::1447::1448::1449::1450::1451::1452::1453::1454::1455::1456::1457::1458::1459::1460::1461::1462::1463::1464::1465::1466::1467::1468::1469::1470::1471::1472::1473::1474::1475::1476::1477::1478::1479::1480::1481::1482::1483::1484::1485::1486::1487::1488::1489::1490::1491::1492::1493::1494::1495::1496::1497::1498::1499::1500::1501::1502::1503::1504::1505::1506::1507::1508::1509::1510::1511::1512::1513::1514::1515::1516::1517::1518::1519::1520::1521::1522::1523::1524::1525::1526::1527::1528::1529::1530::1531::1532::1533::1534::1535::1536::1537::1538::1539::1540::1541::1542::1543::1544::1545::1546::1547::1548::1549::1550::1551::1552::1553::1554::1555::1556::1557::1558::1559::1560::1561::1562::1563::1564::1565::1566::1567::1568::1569::1570::1571::1572::1573::1574::1575::1576::1577::1578::1579::1580::1581::1582::1583::1584::1585::1586::1587::1588::1589::1590::1591::1592::1593::1594::1595::1596::1597::1598::1599::1600::1601::1602::1603::1604::1605::1606::1607::1608::1609::1610::1611::1612::1613::1614::1615::1616::1617::1618::1619::1620::1621::1622::1623::1624::1625::1626::1627::1628::1629::1630::1631::1632::1633::1634::1635::1636::1637::1638::1639::1640::1641::1642::1643::1644::1645::1646::1647::1648::1649::1650::1651::1652::1653::1654::1655::1656::1657::1658::1659::1660::1661::1662::1663::1664::1665::1666::1667::1668::1669::1670::1671::1672::1673::1674::1675::1676::1677::1678::1679::1680::1681::1682::1683::1684::1685::1686::1687::1688::1689::1690::1691::1692::1693::1694::1695::1696::1697::1698::1699::1700::1701::1702::1703::1704::1705::1706::1707::1708::1709::1710::1711::1712::1713::1714::1715::1716::1717::1718::1719::1720::1721::1722::1723::1724::1725::1726::1727::1728::1729::1730::1731::1732::1733::1734::1735::1736::1737::1738::1739::1740::1741::1742::1743::1744::1745::1746::1747::1748::1749::1750::1751::1752::1753::1754::1755::1756::1757::1758::1759::1760::1761::1762::1763::1764::1765::1766::1767::1768::1769::1770::1771::1772::1773::1774::1775::1776::1777::1778::1779::1780::1781::1782::1783::1784::1785::1786::1787::1788::1789::1790::1791::1792::1793::1794::1795::1796::1797::1798::1799::1800::1801::1802::1803::1804::1805::1806::1807::1808::1809::1810::1811::1812::1813::1814::1815::1816::1817::1818::1819::1820::1821::1822::1823::1824::1825::1826::1827::1828::1829::1830::1831::1832::1833::1834::1835::1836::1837::1838::1839::1840::1841::1842::1843::1844::1845::1846::1847::1848::1849::1850::1851::1852::1853::1854::1855::1856::1857::1858::1859::1860::1861::1862::1863::1864::1865::1866::1867::1868::1869::1870::1871::1872::1873::1874::1875::1876::1877::1878::1879::1880::1881::1882::1883::1884::1885::1886::1887::1888::1889::1890::1891::1892::1893::1894::1895::1896::1897::1898::1899::1900::1901::1902::1903::1904::1905::1906::1907::1908::1909::1910::1911::1912::1913::1914::1915::1916::1917::1918::1919::1920::1921::1922::1923::1924::1925::1926::1927::1928::1929::1930::1931::1932::1933::1934::1935::1936::1937::1938::1939::1940::1941::1942::1943::1944::1945::1946::1947::1948::1949::1950::1951::1952::1953::1954::1955::1956::1957::1958::1959::1960::1961::1962::1963::1964::1965::1966::1967::1968::1969::1970::1971::1972::1973::1974::1975::1976::1977::1978::1979::1980::1981::1982::1983::1984::1985::1986::1987::1988::1989::1990::1991::1992::1993::1994::1995::1996::1997::1998::1999::2000::2001::2002::2003::2004::2005::2006::2007::2008::2009::2010::2011::2012::2013::2014::2015::2016::2017::2018::2019::2020::2021::2022::2023::2024::2025::2026::2027::2028::2029::2030::2031::2032::2033::2034::2035::2036::2037::2038::2039::2040::2041::2042::2043::2044::2045::2046::2047::2048::[] # 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::116::117::118::119::120::121::122::123::124::125::126::127::128::129::130::131::132::133::134::135::136::137::138::139::140::141::142::143::144::145::146::147::148::149::150::151::152::153::154::155::156::157::158::159::160::161::162::163::164::165::166::167::168::169::170::171::172::173::174::175::176::177::178::179::180::181::182::183::184::185::186::187::188::189::190::191::192::193::194::195::196::197::198::199::200::201::202::203::204::205::206::207::208::209::210::211::212::213::214::215::216::217::218::219::220::221::222::223::224::225::226::227::228::229::230::231::232::233::234::235::236::237::238::239::240::241::242::243::244::245::246::247::248::249::250::251::252::253::254::255::256::257::258::259::260::261::262::263::264::265::266::267::268::269::270::271::272::273::274::275::276::277::278::279::280::281::282::283::284::285::286::287::288::289::290::291::292::293::294::295::296::297::298::299::300::301::302::303::304::305::306::307::308::309::310::311::312::313::314::315::316::317::318::319::320::321::322::323::324::325::326::327::328::329::330::331::332::333::334::335::336::337::338::339::340::341::342::343::344::345::346::347::348::349::350::351::352::353::354::355::356::357::358::359::360::361::362::363::364::365::366::367::368::369::370::371::372::373::374::375::376::377::378::379::380::381::382::383::384::385::386::387::388::389::390::391::392::393::394::395::396::397::398::399::400::401::402::403::404::405::406::407::408::409::410::411::412::413::414::415::416::417::418::419::420::421::422::423::424::425::426::427::428::429::430::431::432::433::434::435::436::437::438::439::440::441::442::443::444::445::446::447::448::449::450::451::452::453::454::455::456::457::458::459::460::461::462::463::464::465::466::467::468::469::470::471::472::473::474::475::476::477::478::479::480::481::482::483::484::485::486::487::488::489::490::491::492::493::494::495::496::497::498::499::500::501::502::503::504::505::506::507::508::509::510::511::512::513::514::515::516::517::518::519::520::521::522::523::524::525::526::527::528::529::530::531::532::533::534::535::536::537::538::539::540::541::542::543::544::545::546::547::548::549::550::551::552::553::554::555::556::557::558::559::560::561::562::563::564::565::566::567::568::569::570::571::572::573::574::575::576::577::578::579::580::581::582::583::584::585::586::587::588::589::590::591::592::593::594::595::596::597::598::599::600::601::602::603::604::605::606::607::608::609::610::611::612::613::614::615::616::617::618::619::620::621::622::623::624::625::626::627::628::629::630::631::632::633::634::635::636::637::638::639::640::641::642::643::644::645::646::647::648::649::650::651::652::653::654::655::656::657::658::659::660::661::662::663::664::665::666::667::668::669::670::671::672::673::674::675::676::677::678::679::680::681::682::683::684::685::686::687::688::689::690::691::692::693::694::695::696::697::698::699::700::701::702::703::704::705::706::707::708::709::710::711::712::713::714::715::716::717::718::719::720::721::722::723::724::725::726::727::728::729::730::731::732::733::734::735::736::737::738::739::740::741::742::743::744::745::746::747::748::749::750::751::752::753::754::755::756::757::758::759::760::761::762::763::764::765::766::767::768::769::770::771::772::773::774::775::776::777::778::779::780::781::782::783::784::785::786::787::788::789::790::791::792::793::794::795::796::797::798::799::800::801::802::803::804::805::806::807::808::809::810::811::812::813::814::815::816::817::818::819::820::821::822::823::824::825::826::827::828::829::830::831::832::833::834::835::836::837::838::839::840::841::842::843::844::845::846::847::848::849::850::851::852::853::854::855::856::857::858::859::860::861::862::863::864::865::866::867::868::869::870::871::872::873::874::875::876::877::878::879::880::881::882::883::884::885::886::887::888::889::890::891::892::893::894::895::896::897::898::899::900::901::902::903::904::905::906::907::908::909::910::911::912::913::914::915::916::917::918::919::920::921::922::923::924::925::926::927::928::929::930::931::932::933::934::935::936::937::938::939::940::941::942::943::944::945::946::947::948::949::950::951::952::953::954::955::956::957::958::959::960::961::962::963::964::965::966::967::968::969::970::971::972::973::974::975::976::977::978::979::980::981::982::983::984::985::986::987::988::989::990::991::992::993::994::995::996::997::998::999::1000::1001::1002::1003::1004::1005::1006::1007::1008::1009::1010::1011::1012::1013::1014::1015::1016::1017::1018::1019::1020::1021::1022::1023::1024::1025::1026::1027::1028::1029::1030::1031::1032::1033::1034::1035::1036::1037::1038::1039::1040::1041::1042::1043::1044::1045::1046::1047::1048::1049::1050::1051::1052::1053::1054::1055::1056::1057::1058::1059::1060::1061::1062::1063::1064::1065::1066::1067::1068::1069::1070::1071::1072::1073::1074::1075::1076::1077::1078::1079::1080::1081::1082::1083::1084::1085::1086::1087::1088::1089::1090::1091::1092::1093::1094::1095::1096::1097::1098::1099::1100::1101::1102::1103::1104::1105::1106::1107::1108::1109::1110::1111::1112::1113::1114::1115::1116::1117::1118::1119::1120::1121::1122::1123::1124::1125::1126::1127::1128::1129::1130::1131::1132::1133::1134::1135::1136::1137::1138::1139::1140::1141::1142::1143::1144::1145::1146::1147::1148::1149::1150::1151::1152::1153::1154::1155::1156::1157::1158::1159::1160::1161::1162::1163::1164::1165::1166::1167::1168::1169::1170::1171::1172::1173::1174::1175::1176::1177::1178::1179::1180::1181::1182::1183::1184::1185::1186::1187::1188::1189::1190::1191::1192::1193::1194::1195::1196::1197::1198::1199::1200::1201::1202::1203::1204::1205::1206::1207::1208::1209::1210::1211::1212::1213::1214::1215::1216::1217::1218::1219::1220::1221::1222::1223::1224::1225::1226::1227::1228::1229::1230::1231::1232::1233::1234::1235::1236::1237::1238::1239::1240::1241::1242::1243::1244::1245::1246::1247::1248::1249::1250::1251::1252::1253::1254::1255::1256::1257::1258::1259::1260::1261::1262::1263::1264::1265::1266::1267::1268::1269::1270::1271::1272::1273::1274::1275::1276::1277::1278::1279::1280::1281::1282::1283::1284::1285::1286::1287::1288::1289::1290::1291::1292::1293::1294::1295::1296::1297::1298::1299::1300::1301::1302::1303::1304::1305::1306::1307::1308::1309::1310::1311::1312::1313::1314::1315::1316::1317::1318::1319::1320::1321::1322::1323::1324::1325::1326::1327::1328::1329::1330::1331::1332::1333::1334::1335::1336::1337::1338::1339::1340::1341::1342::1343::1344::1345::1346::1347::1348::1349::1350::1351::1352::1353::1354::1355::1356::1357::1358::1359::1360::1361::1362::1363::1364::1365::1366::1367::1368::1369::1370::1371::1372::1373::1374::1375::1376::1377::1378::1379::1380::1381::1382::1383::1384::1385::1386::1387::1388::1389::1390::1391::1392::1393::1394::1395::1396::1397::1398::1399::1400::1401::1402::1403::1404::1405::1406::1407::1408::1409::1410::1411::1412::1413::1414::1415::1416::1417::1418::1419::1420::1421::1422::1423::1424::1425::1426::1427::1428::1429::1430::1431::1432::1433::1434::1435::1436::1437::1438::1439::1440::1441::1442::1443::1444::1445::1446::1447::1448::1449::1450::1451::1452::1453::1454::1455::1456::1457::1458::1459::1460::1461::1462::1463::1464::1465::1466::1467::1468::1469::1470::1471::1472::1473::1474::1475::1476::1477::1478::1479::1480::1481::1482::1483::1484::1485::1486::1487::1488::1489::1490::1491::1492::1493::1494::1495::1496::1497::1498::1499::1500::1501::1502::1503::1504::1505::1506::1507::1508::1509::1510::1511::1512::1513::1514::1515::1516::1517::1518::1519::1520::1521::1522::1523::1524::1525::1526::1527::1528::1529::1530::1531::1532::1533::1534::1535::1536::1537::1538::1539::1540::1541::1542::1543::1544::1545::1546::1547::1548::1549::1550::1551::1552::1553::1554::1555::1556::1557::1558::1559::1560::1561::1562::1563::1564::1565::1566::1567::1568::1569::1570::1571::1572::1573::1574::1575::1576::1577::1578::1579::1580::1581::1582::1583::1584::1585::1586::1587::1588::1589::1590::1591::1592::1593::1594::1595::1596::1597::1598::1599::1600::1601::1602::1603::1604::1605::1606::1607::1608::1609::1610::1611::1612::1613::1614::1615::1616::1617::1618::1619::1620::1621::1622::1623::1624::1625::1626::1627::1628::1629::1630::1631::1632::1633::1634::1635::1636::1637::1638::1639::1640::1641::1642::1643::1644::1645::1646::1647::1648::1649::1650::1651::1652::1653::1654::1655::1656::1657::1658::1659::1660::1661::1662::1663::1664::1665::1666::1667::1668::1669::1670::1671::1672::1673::1674::1675::1676::1677::1678::1679::1680::1681::1682::1683::1684::1685::1686::1687::1688::1689::1690::1691::1692::1693::1694::1695::1696::1697::1698::1699::1700::1701::1702::1703::1704::1705::1706::1707::1708::1709::1710::1711::1712::1713::1714::1715::1716::1717::1718::1719::1720::1721::1722::1723::1724::1725::1726::1727::1728::1729::1730::1731::1732::1733::1734::1735::1736::1737::1738::1739::1740::1741::1742::1743::1744::1745::1746::1747::1748::1749::1750::1751::1752::1753::1754::1755::1756::1757::1758::1759::1760::1761::1762::1763::1764::1765::1766::1767::1768::1769::1770::1771::1772::1773::1774::1775::1776::1777::1778::1779::1780::1781::1782::1783::1784::1785::1786::1787::1788::1789::1790::1791::1792::1793::1794::1795::1796::1797::1798::1799::1800::1801::1802::1803::1804::1805::1806::1807::1808::1809::1810::1811::1812::1813::1814::1815::1816::1817::1818::1819::1820::1821::1822::1823::1824::1825::1826::1827::1828::1829::1830::1831::1832::1833::1834::1835::1836::1837::1838::1839::1840::1841::1842::1843::1844::1845::1846::1847::1848::1849::1850::1851::1852::1853::1854::1855::1856::1857::1858::1859::1860::1861::1862::1863::1864::1865::1866::1867::1868::1869::1870::1871::1872::1873::1874::1875::1876::1877::1878::1879::1880::1881::1882::1883::1884::1885::1886::1887::1888::1889::1890::1891::1892::1893::1894::1895::1896::1897::1898::1899::1900::1901::1902::1903::1904::1905::1906::1907::1908::1909::1910::1911::1912::1913::1914::1915::1916::1917::1918::1919::1920::1921::1922::1923::1924::1925::1926::1927::1928::1929::1930::1931::1932::1933::1934::1935::1936::1937::1938::1939::1940::1941::1942::1943::1944::1945::1946::1947::1948::1949::1950::1951::1952::1953::1954::1955::1956::1957::1958::1959::1960::1961::1962::1963::1964::1965::1966::1967::1968::1969::1970::1971::1972::1973::1974::1975::1976::1977::1978::1979::1980::1981::1982::1983::1984::1985::1986::1987::1988::1989::1990::1991::1992::1993::1994::1995::1996::1997::1998::1999::2000::2001::2002::2003::2004::2005::2006::2007::2008::2009::2010::2011::2012::2013::2014::2015::2016::2017::2018::2019::2020::2021::2022::2023::2024::2025::2026::2027::2028::2029::2030::2031::2032::2033::2034::2035::2036::2037::2038::2039::2040::2041::2042::2043::2044::2045::2046::2047::2048::2049::[] # ./build/list: simulated 0 seconds