jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all

오늘도 malloc 이다

일주일동안 하나 붙잡고 있으니…

오히려 좋아

점수 안높아진게 충격이라 왜 그런지 한번 살펴보았다


| Trace | A util | A secs (μs) | A Kops  | B util | B secs (μs) | B Kops  | B/A secs× |
| ----- | ------ | ----------- | ------- | ------ | ----------- | ------- | --------- |
| 0     | 89%    | 91.000      | 62,571  | 91%    | 813.000     | 7,004   | 8.93×     |
| 1     | 92%    | 52.112      | 112,220 | 91%    | 524.000     | 11,160  | 10.06×    |
| 2     | 94%    | 128.000     | 51,938  | 96%    | 1564.000    | 4,251   | 12.22×    |
| 3     | 96%    | 88.000      | 61,136  | 96%    | 1576.000    | 3,414   | 17.91×    |
| 4     | 66%    | 65.221      | 220,787 | 66%    | 52.276      | 275,462 | 0.80×     |
| 5     | 88%    | 266.000     | 18,045  | 90%    | 1947.000    | 2,465   | 7.32×     |
| 6     | 85%    | 272.000     | 17,647  | 88%    | 1837.000    | 2,613   | 6.75×     |
| 7     | 55%    | 652.000     | 18,405  | 55%    | 5564.000    | 2,157   | 8.53×     |
| 8     | 51%    | 667.000     | 35,982  | 51%    | 5111.000    | 4,696   | 7.66×     |
| 9     | 33%    | 11277.000   | 1,277   | 27%    | 19045.000   | 756     | 1.69×     |
| 10    | 30%    | 147.000     | 97,966  | 43%    | 339.000     | 42,481  | 2.31×     |
| Total | 71%    | 13706.000   | 8,199   | 72%    | 38372.000   | 2,928   | 2.80×     |

보아하니 속도가 월등히 높아졌음에도 동점인 걸 보니… 속도는 40점이 만점이란 걸 알 수 있다

여기서 더 점수를 높이려면 util을 높여야 한다는 거다

그래서 find_fit을 first fit에서 best fit으로 교체했다



static void *find_fit(size_t asize) {
    for (void *bp = free_head; bp != NULL; bp = GET_SUCC(bp)) {
        if (GET_SIZE(HDRP(bp)) >= asize) return bp;
    }
    return NULL;
}

🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽
           전환
🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽

static void *find_fit(size_t asize) {
    void *best = NULL;
    size_t best_size = __SIZE_MAX__;
    for (void *bp = free_head; bp != NULL; bp = GET_SUCC(bp)) {
        size_t csize = GET_SIZE(HDRP(bp));   // 매 반복마다 갱신
        if (csize < asize) continue;

        // 완벽 적합 → 즉시 반환
        if (csize == asize) return bp;

        // 더 작은 후보면 갱신
        if (csize < best_size) {
            best = bp;
            best_size = csize;

        // 남는 조각이 분할 불가면 사실상 perfect fit로 보고 바로 선택
        if (best_size - asize < MIN_BLOCK) return best;
        }
    }
    return best; // 없으면 NULL
}


다행히도 효과가 있었다

Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.000129 44208
 1       yes   99%    5848  0.000147 39755
 2       yes   99%    6648  0.000153 43338
 3       yes   99%    5380  0.000122 44280
 4       yes   66%   14400  0.000125115477
 5       yes   96%    4800  0.003742  1283
 6       yes   95%    4800  0.003105  1546
 7       yes   55%   12000  0.009270  1295
 8       yes   51%   24000  0.031829   754
 9       yes   28%   14401  0.000177 81454
10       yes   35%   14401  0.000117122875
Total          75%  112372  0.048915  2297

Perf index = 45 (util) + 40 (thru) = 85/100

어제보다 2점 올랐다…

음… 7~10이 뭔지는 몰라도 저기서 유틸이 박살난다


진짜 뭐지?

왜 유틸 꼴아박는지 모르겠다…

청크 사이즈 줄이기 같은 간단한 거 테스트 해보며 원인을 찾아가야겠다


그전에

driver를 -V로 실행해 쬐금 더 자세히 디버그 가능한 걸 알게 되었다

0. Reading tracefile: amptjp-bal.rep
1. Reading tracefile: cccp-bal.rep
2. Reading tracefile: cp-decl-bal.rep
3. Reading tracefile: expr-bal.rep
4. Reading tracefile: coalescing-bal.rep
5. Reading tracefile: random-bal.rep
6. Reading tracefile: random2-bal.rep
7. Reading tracefile: binary-bal.rep
8. Reading tracefile: binary2-bal.rep
9. Reading tracefile: realloc-bal.rep
10. Reading tracefile: realloc2-bal.rep

대충 이런식인 거 같다 7번부터 문제가 생기니

7. Reading tracefile: binary-bal.rep
8. Reading tracefile: binary2-bal.rep
9. Reading tracefile: realloc-bal.rep
10. Reading tracefile: realloc2-bal.rep

여기에 있는 테스트 케이스들을 살펴봐야겠다
현재 realloc을 우측 확장과 병합으로만 구현했는데 좌측도 구현해야 할듯 싶다
으윽… 그거까진 싫은데…


    // 좌측 확장
    if (!GET_PREV_ALLOC(HDRP(ptr))) {           
        void *prev = PREV_BLKP(ptr);
        if (!GET_ALLOC(HDRP(prev))) {
            size_t psize = GET_SIZE(HDRP(prev));
            if (psize + oldsize >= asize) {
                UNLINK(prev);
                size_t copysize = (size < payload) ? size : payload;
                memmove(prev, ptr, copysize);
                PUT(HDRP(prev), PACK(psize + oldsize, GET_PREV_ALLOC(HDRP(prev)) | FL_ALLOC));
                split_tail(prev, asize);
                return prev;
            }
            /* 우측도 확장 (양쪽 확장) */
            if (!GET_ALLOC(HDRP(next))) {
                size_t nsize = GET_SIZE(HDRP(next));
                if (psize + oldsize + nsize >= asize) {
                    UNLINK(prev);
                    UNLINK(next);
                    size_t combined = psize + oldsize + nsize;
                    size_t copySize = (size < payload) ? size : payload;
                    memmove(prev, ptr, copySize);
                    PUT(HDRP(prev), PACK(combined, GET_PREV_ALLOC(HDRP(prev)) | FL_ALLOC));
                    split_tail(prev, asize);
                    return prev;
                }
            }
        }
    }

대충 좌측있는지 확인하고 좌측 블록 크기 합쳐서 원하는 사이즈보다 크면 진행하고 아니면 우측도 확인하는 방식이다

return할때 이전 블록 포인터 반환한다는 거에 유의하면 그리 어렵지는 않다


사실 어렵다

그리고 이렇게까지 한 결과…

1점 올랐다…

trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.000138 41351
 1       yes   99%    5848  0.000150 39013
 2       yes   99%    6648  0.000217 30608
 3       yes   99%    5380  0.000119 45363
 4       yes   66%   14400  0.000105137667
 5       yes   96%    4800  0.003092  1553
 6       yes   95%    4800  0.002975  1614
 7       yes   55%   12000  0.009536  1258
 8       yes   51%   24000  0.032589   736
 9       yes   41%   14401  0.000244 58924
10       yes   45%   14401  0.000141102280
Total          77%  112372  0.049304  2279

Perf index = 46 (util) + 40 (thru) = 86/100

그래도 28%, 35% 에서 41%, 45%가 되었는데 드라마틱하게 오르지는 않은 모양이다

흠… 더 뭐해야 될지 모르는데;;

지금 굳이 분리 접합 그런걸로 넘어갈 필요 없이 유틸을 더 높여야 될듯하다

그러다가 속도 딸리면 분리 접합으로 넘어가고



일단은 늘어나는 청크 사이즈부터 손좀 봐야겠다 싶다

어차피 지금은 무푸터 정책이니 굳이 푸터블록까지 걱정해줄 필요 없다

할당할때는 푸터 버리니까 말이다

WSIZE*2 더해주던 거 WSIZE 하나로 바꿨다

이로써 과하게 더해주던 블록을 조금 아꼈다…

이렇게 바이트 아끼다 부자 되게 생겼다

#define ALLOC_OVERHEAD WSIZE

static inline size_t req_asize(size_t size) {
    size_t a = ALIGN(size + ALLOC_OVERHEAD);   /* 헤더만 포함 */
    if (a < MIN_BLOCK) a = MIN_BLOCK;          /* 최소 자유블록 크기 보장 */
    return a;
}

이렇게 새로 쓸거 만들어주고

void *mm_malloc(size_t size) {
    if (size == 0) return NULL;
//  size_t asize = MAX(MIN_BLOCK, ALIGN(size + OVERHEAD)); 이거에서
    size_t asize = req_asize(size);               //    << 이걸로
    ...
}


void *mm_realloc(void *ptr, size_t size) {
    ...
    size_t oldsize    = GET_SIZE(HDRP(ptr));
//  size_t payload = oldsize - OVERHEAD;       OVERHEAD = 2*WSIZE
    size_t oldpayload = oldsize - WSIZE;       // WSIZE하나로 교체
//  size_t asize = MAX(MIN_BLOCK, ALIGN(size + OVERHEAD));  이거에서
    size_t asize      = req_asize(size);           //    << 이걸로
    ...
}

malloc하고 realloc에서 교체 해주었다

ㅅㅂ 1점도 안올랐다

티끌 모아봤자 티끌이다

설명


청크사이즈 개선하러 가자



우선 realloc의 힙익스텐드를 개선했다

if (extend_heap((asize + WSIZE - 1) / WSIZE) != NULL)

이런식으로 그냥 asize만큼 확장했는데 이를 해결하기 위해


size_t need = asize - oldsize;
if (extend_heap((need + WSIZE - 1) / WSIZE) != NULL)

need 변수를 도입해 확장하는 양을 좀 줄였다

으음… 이게 문제가 아니었는지 딱히 안올랐다

그래도 일단은 다 해볼 생각이다

그 다음에 malloc에서 속도 희생하고 유틸을 높이기 위해
asize가 청크사이즈보다 작다면 청크사이즈만큼 늘리던걸 무조건 asize만큼 늘리게 바꿨다

extendsize = MAX(asize, CHUNKSIZE);
if ((bp = extend_heap(extendsize/WSIZE)) == NULL)
    return NULL;
place(bp, asize);
return bp;

🔽🔽🔽🔽🔽🔽🔽🔽🔽
         변경
🔽🔽🔽🔽🔽🔽🔽🔽🔽

extendsize = asize;
if ((bp = extend_heap((extendsize + WSIZE - 1)/WSIZE)) == NULL)
    return NULL;
place(bp, asize);
return bp;

속도가 떨어졌지만 점수가 깍일 정도는 아니었고…

3점이나 올랐다!!!

trace 10에서 상당히 히트인걸 보니 realloc 잔뜩 했나 보다

Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.000133 42941
 1       yes  100%    5848  0.000141 41358
 2       yes   99%    6648  0.000155 42890
 3       yes  100%    5380  0.000112 48165
 4       yes   66%   14400  0.000135106746
 5       yes   96%    4800  0.002973  1615
 6       yes   95%    4800  0.003240  1482
 7       yes   55%   12000  0.008204  1463
 8       yes   51%   24000  0.017505  1371
 9       yes   45%   14401  0.000105137283
10       yes   87%   14401  0.000056258082
Total          81%  112372  0.032758  3430

Perf index = 49 (util) + 40 (thru) = 89/100

잘하면 90점 넘길 수 있겠다

util을 어떻게든 끌어올려야겠다


지금 보니 4번도 util이 영 시원찮다 병합의 효율을 올리면 realloc이랑 다른 것도 오를 거 같으니 수정해보아야겠다

병합 case 4에서 푸터 prev_block말고 next_block을 가리키던 오류 하나 수정하고
mm_init에서 초기에 힙 영역 확장하는게 문제라며 제거하고 초기 할당할때 불러오게 바꿨다
그리 효과 있을지 모르곘다


…?


Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.000129 44071
 1       yes  100%    5848  0.000142 41329
 2       yes   99%    6648  0.000167 39856
 3       yes  100%    5380  0.000124 43387
 4       yes  100%   14400  0.000088163080
 5       yes   96%    4800  0.002960  1622
 6       yes   95%    4800  0.003196  1502
 7       yes   55%   12000  0.008483  1415
 8       yes   51%   24000  0.032008   750
 9       yes  100%   14401  0.000116124147
10       yes   87%   14401  0.000118121836
Total          89%  112372  0.047531  2364

Perf index = 54 (util) + 40 (thru) = 94/100

머임??????

점수 떡상했다 emoji


오류 수정때문에 많이 오른 건 아니고
mm_init에서 초기 청크사이즈 불러오는 거 제거했더니 util이 잔뜩 올랐다

현재 점수를 깍아먹던 realloc의 트레이스 경우
4095 → 4095 → free 둘 다 → 8190 라는 패턴이 반복된다
그리고 현재 이를

  • 4095 요청 → asize = ALIGN(4095 + 4) = 4104
  • 8190 요청 → asize = ALIGN(8190 + 4) = 8200

이렇게 처리하는데 초기힙을 CHUNKSIZE로 받게 해놓아 4096B가 미리 있다는 거다
그러니 4104B가 4096B에 안들어가 추가 확장 일어나고 이에 따라 계속해서 4096 vs 4104가 엇갈리며 자투리(4096) 블록이 남는다

그 자투리로는 다음 4104B를 못 받으니 또 확장을 반복하게 되어 최종힙이 쓸데 없이 커지는 거였다…

trace 안뜯어 봤으면 ㄹㅇ 절대 몰랐을 건데

해결은 의외로 간단히 되었다

…아닌가?

그냥 오류 수정해서 그런건가?

솔직히 잘 모르겠다


이정도면 여기서 하루 시마이쳐도 나쁘지 않지만
이렇게 된 거 trace 10도 한번 알아보자

trace 10의 경우는 단순히 큰 블록만 붙이는게 아니라 강 약 강 약 섞어서 쬐깐이들을 던진다

그러면서 강 블록 해제하고 살짝 더 키운 거 던져서 제자리 할당 못하고 새로 확장하게 한다

이때문에 개같은 거 효율이 안나온다 강 뒤에 붙은 쬐깐이 떼주는 함수 만들어 쇼부 봐야한다

그래서 어캐함?