AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/* External functions from mem2.c (globally visible due to build flags) */9extern void test_adjustStats(int iSize, int increment);10extern void sqlite3MemdebugDump(const char *zFilename);11extern int sqlite3MemdebugMallocCount(void);12 13/* Local constant mirroring mem2.c */14#define NCSIZE_TEST 100015 16static int dumpCounter = 0;17 18/* Helper: compute bucket index from size using ROUND8 and clamping */19static int bucket_index_from_size(int iSize){20 int i = ROUND8(iSize)/8;21 if( i > NCSIZE_TEST-1 ) i = NCSIZE_TEST-1;22 if( i < 0 ) i = 0;23 return i;24}25 26/* Helper: parse the COUNTS section from a memdebug dump file */27static void parse_counts_file(const char *path, int *alloc, int *current, int *mx){28 FILE *f = fopen(path, "r");29 TEST_ASSERT_MESSAGE(f != NULL, "Failed to open memdebug dump file");30 31 char line[512];32 int inCounts = 0;33 /* Initialize arrays to zero */34 for( int i = 0; i < NCSIZE_TEST; i++ ){35 alloc[i] = 0;36 current[i] = 0;37 mx[i] = 0;38 }39 40 while( fgets(line, sizeof(line), f) ){41 if( !inCounts ){42 if( strncmp(line, "COUNTS:", 7) == 0 ){43 inCounts = 1;44 }45 }else{46 int bytes = 0, a = 0, c = 0, m = 0;47 /* Lines look like: " %5d: %10d %10d %10d\n" */48 if( sscanf(line, " %d: %d %d %d", &bytes, &a, &c, &m) == 4 ){49 int idx = bytes / 8;50 if( idx >= 0 && idx < NCSIZE_TEST ){51 alloc[idx] = a;52 current[idx] = c;53 mx[idx] = m;54 }55 }56 }57 }58 fclose(f);59}60 61/* Helper: dump current memory debug state and parse out counters */62static void snapshot_counts(int *alloc, int *current, int *mx){63 char fname[128];64 snprintf(fname, sizeof(fname), "mem2_counts_snapshot_%d.txt", ++dumpCounter);65 sqlite3MemdebugDump(fname);66 parse_counts_file(fname, alloc, current, mx);67 remove(fname);68}69 70void setUp(void) {71 /* No special setup required */72}73 74void tearDown(void) {75 /* No special teardown required */76}77 78/* Test that increments go to the correct rounded bucket and update counts */79void test_adjustStats_increments_and_rounding(void){80 int beforeAlloc[NCSIZE_TEST], beforeCur[NCSIZE_TEST], beforeMx[NCSIZE_TEST];81 int afterAlloc[NCSIZE_TEST], afterCur[NCSIZE_TEST], afterMx[NCSIZE_TEST];82 83 /* Snapshot before */84 int totalBefore = sqlite3MemdebugMallocCount();85 snapshot_counts(beforeAlloc, beforeCur, beforeMx);86 87 /* Sizes chosen to exercise rounding and multiple buckets */88 int sizes[] = { 0, 1, 7, 8, 9, 15, 16, 24, 25, 1003 };89 int nSizes = (int)(sizeof(sizes)/sizeof(sizes[0]));90 91 /* Track expected increments per bucket */92 int incPerBucket[NCSIZE_TEST];93 memset(incPerBucket, 0, sizeof(incPerBucket));94 95 for( int i = 0; i < nSizes; i++ ){96 int idx = bucket_index_from_size(sizes[i]);97 incPerBucket[idx]++;98 test_adjustStats(sizes[i], +1);99 }100 101 /* Snapshot after */102 int totalAfter = sqlite3MemdebugMallocCount();103 snapshot_counts(afterAlloc, afterCur, afterMx);104 105 /* Verify total allocation count delta */106 TEST_ASSERT_EQUAL_INT_MESSAGE(nSizes, totalAfter - totalBefore,107 "Total alloc count delta mismatch");108 109 /* Verify per-bucket deltas and mx invariants */110 for( int i = 0; i < NCSIZE_TEST; i++ ){111 if( incPerBucket[i] > 0 ){112 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeAlloc[i] + incPerBucket[i], afterAlloc[i],113 "nAlloc per-bucket increment mismatch");114 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeCur[i] + incPerBucket[i], afterCur[i],115 "nCurrent per-bucket increment mismatch");116 TEST_ASSERT_TRUE_MESSAGE(afterMx[i] >= beforeMx[i],117 "mxCurrent should not decrease");118 TEST_ASSERT_TRUE_MESSAGE(afterMx[i] >= afterCur[i],119 "mxCurrent should be >= current");120 }121 }122}123 124/* Test that decrements reduce current without affecting alloc and that mx reaches the high-water mark */125void test_adjustStats_decrement_balances_current_and_mx(void){126 int beforeAlloc[NCSIZE_TEST], beforeCur[NCSIZE_TEST], beforeMx[NCSIZE_TEST];127 int afterAlloc[NCSIZE_TEST], afterCur[NCSIZE_TEST], afterMx[NCSIZE_TEST];128 129 /* Choose a size and repeat count for a single bucket */130 int size = 12345; /* arbitrary mid-range size */131 int idx = bucket_index_from_size(size);132 int k = 5;133 134 int totalBefore = sqlite3MemdebugMallocCount();135 snapshot_counts(beforeAlloc, beforeCur, beforeMx);136 137 for( int i = 0; i < k; i++ ){138 test_adjustStats(size, +1);139 }140 for( int i = 0; i < k; i++ ){141 test_adjustStats(size, -1);142 }143 144 int totalAfter = sqlite3MemdebugMallocCount();145 snapshot_counts(afterAlloc, afterCur, afterMx);146 147 /* nAlloc increases by k (decrements do not affect nAlloc) */148 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeAlloc[idx] + k, afterAlloc[idx],149 "nAlloc should increase only by number of increments");150 151 /* nCurrent returns to its original value after k increments then k decrements */152 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeCur[idx], afterCur[idx],153 "nCurrent should return to original after balanced decs");154 155 /* mxCurrent should be at least max(beforeMx, beforeCur + k) */156 {157 int expectedMinMx = beforeCur[idx] + k;158 if( expectedMinMx < beforeMx[idx] ) expectedMinMx = beforeMx[idx];159 TEST_ASSERT_TRUE_MESSAGE(afterMx[idx] >= expectedMinMx,160 "mxCurrent did not reach expected high-water mark");161 }162 163 /* Total malloc count reflects only increments */164 TEST_ASSERT_EQUAL_INT_MESSAGE(k, totalAfter - totalBefore,165 "Total alloc count delta mismatch for inc/dec test");166}167 168/* Test that very large sizes clamp to the last bucket (index NCSIZE-1) */169void test_adjustStats_clamps_to_last_bucket(void){170 int beforeAlloc[NCSIZE_TEST], beforeCur[NCSIZE_TEST], beforeMx[NCSIZE_TEST];171 int afterAlloc[NCSIZE_TEST], afterCur[NCSIZE_TEST], afterMx[NCSIZE_TEST];172 173 const int lastIdx = NCSIZE_TEST - 1;174 /* Choose a size well beyond the last bucket to force clamping */175 int hugeSize = 8 * (NCSIZE_TEST + 500); /* clearly beyond */176 177 TEST_ASSERT_EQUAL_INT(lastIdx, bucket_index_from_size(hugeSize));178 179 int totalBefore = sqlite3MemdebugMallocCount();180 snapshot_counts(beforeAlloc, beforeCur, beforeMx);181 182 int reps = 3;183 for( int i = 0; i < reps; i++ ){184 test_adjustStats(hugeSize, +1);185 }186 187 int totalAfter = sqlite3MemdebugMallocCount();188 snapshot_counts(afterAlloc, afterCur, afterMx);189 190 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeAlloc[lastIdx] + reps, afterAlloc[lastIdx],191 "Last bucket nAlloc mismatch");192 TEST_ASSERT_EQUAL_INT_MESSAGE(beforeCur[lastIdx] + reps, afterCur[lastIdx],193 "Last bucket nCurrent mismatch");194 TEST_ASSERT_TRUE_MESSAGE(afterMx[lastIdx] >= beforeMx[lastIdx],195 "Last bucket mxCurrent should not decrease");196 TEST_ASSERT_TRUE_MESSAGE(afterMx[lastIdx] >= afterCur[lastIdx],197 "Last bucket mxCurrent should be >= current");198 TEST_ASSERT_EQUAL_INT_MESSAGE(reps, totalAfter - totalBefore,199 "Total alloc count delta mismatch for clamp test");200}201 202int main(void){203 UNITY_BEGIN();204 RUN_TEST(test_adjustStats_increments_and_rounding);205 RUN_TEST(test_adjustStats_decrement_balances_current_and_mx);206 RUN_TEST(test_adjustStats_clamps_to_last_bucket);207 return UNITY_END();208}