Commit 2398f91b9dcbcb31ab94598e501261c0c4cc695f

Lecture 3 work.
  
1membench-malloc
2membench-jemalloc
3membench-tcmalloc
4membench-arena
  
1PROGRAMS = $(patsubst mb-%.c,membench-%,$(wildcard mb-*.c))
2ifeq ($(strip $(shell ld -jemalloc 2>&1 | grep -- -ljemalloc)),)
3PROGRAMS += membench-jemalloc
4endif
5ifneq ($(wildcard /usr/lib/libtcmalloc.so.4),)
6PROGRAMS += membench-tcmalloc
7endif
8all: $(PROGRAMS)
9
10DEFS += -pthread
11include ../common/rules.mk
12
13%.o: %.c $(BUILDSTAMP)
14 $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCFLAGS) $(O) -o $@ -c $<
15
16membench-%: membench.o mb-%.o
17 $(CC) $(CFLAGS) $(O) -o $@ $^
18
19membench-jemalloc: membench.o mb-malloc.o
20 $(CC) $(CFLAGS) $(O) -o $@ $^ -ljemalloc
21
22membench-tcmalloc: membench.o mb-malloc.o
23 $(CC) $(CFLAGS) $(O) -o $@ $^ /usr/lib/libtcmalloc.so.4
24
25clean:
26 rm -f *.o $(PROGRAMS)
27 rm -rf $(DEPSDIR) *.dSYM
28
29.PHONY: all clean
  
1#include "membench.h"
2#include <stdlib.h>
3#include <assert.h>
4
5/*
6
7Normally, we allocate and free dynamic objects independently, as
8`malloc` and `free` do. But we can obtain performance benefits, and
9some neat features, by allocating and freeing related objects in
10groups.
11
12An *arena* (also called a zone, area, pool, memory context, etc.)
13formalizes this concept. An arena is a type that represents a group of
14allocated objects. Special functions are used to allocate and free
15objects from this arena. Those special functions can be faster, more
16convenient, and sometimes safer than general-purpose `malloc` and
17`free`.
18
19Below is the start of an arena allocator for `chunk` objects---but it
20only knows how to allocate one chunk. Finish the allocator! Your
21allocator should:
22
23* Allocate a chunk in O(1) time.
24* Free a chunk in O(1) time.
25* Use memory proportional to the peak number of actively allocated
26chunks (rather than, say, the total number of allocated chunks).
27* Run out of memory only if the system has no more memory available.
28
29More on arenas:
30https://en.wikipedia.org/wiki/Region-based_memory_management
31
32See "membench.h" for function semantics.
33
34*/
35
36
37// A `free_chunk` was allocated by the arena, but isn't currently in
38// use. You'll likely put some bookkeeping information into such chunks.
39typedef struct {
40 // YOUR CODE HERE
41} free_chunk;
42
43// A `chunk_or_free` object is *either* an allocated chunk, *or* a
44// free chunk. That calls for a union!
45typedef union {
46 chunk c;
47 free_chunk f;
48} chunk_or_free;
49
50#define GROUPSIZE 1
51typedef struct membench_group {
52 chunk_or_free chunks[GROUPSIZE];
53} membench_group;
54
55struct membench_arena {
56 membench_group first_group;
57 chunk_or_free* free_chunk;
58};
59
60
61membench_arena* membench_arena_new(void) {
62 // An arena initially contains a single chunk, which is free.
63 // TODO: Change this!
64 membench_arena* arena = (membench_arena*) malloc(sizeof(membench_arena));
65 arena->free_chunk = &arena->first_group.chunks[0];
66 return arena;
67}
68
69chunk* membench_alloc(membench_arena* arena) {
70 assert(arena->free_chunk != NULL);
71 chunk* result = &arena->free_chunk->c;
72 arena->free_chunk = NULL;
73 return result;
74}
75
76void membench_free(membench_arena* arena, chunk* x) {
77 arena->free_chunk = (chunk_or_free*) x;
78}
79
80void membench_arena_free(membench_arena* arena) {
81 free(arena);
82}
  
1#include "membench.h"
2#include <stdlib.h>
3
4// membench_arena_new()
5// Allocate and initialize a new arena, returning the arena.
6membench_arena* membench_arena_new(void) {
7 return NULL;
8}
9
10// membench_alloc(arena)
11// Allocate and return a new chunk using the arena.
12chunk* membench_alloc(membench_arena* arena) {
13 (void) arena;
14 return (chunk*) malloc(sizeof(chunk));
15}
16
17// membench_free(arena)
18// Free a chunk `x` that was previously allocated from this arena.
19//
20// REQUIREMENT: `x` was previously returned by
21// `membench_alloc(arena)` for this arena, and not previously
22// freed, and `x != NULL`.
23void membench_free(membench_arena* arena, chunk* x) {
24 (void) arena;
25 free(x);
26}
27
28void membench_arena_free(membench_arena* arena) {
29 (void) arena;
30}
  
1#include "membench.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <pthread.h>
5#include <assert.h>
6#include <getopt.h>
7
8static unsigned n = 50000000;
9static unsigned k = 4096;
10
11void benchmark(void) {
12 // Allocate a new memory arena for this thread.
13 // An "arena" is an object that encapsulates a set of memory allocations.
14 // Arenas can capture allocation statistics and improve speed.
15 membench_arena* arena = membench_arena_new();
16
17 // Allocate `k` chunks.
18 chunk** cs = (chunk**) malloc(sizeof(chunk*) * k);
19 for (unsigned i = 0; i != k; ++i) {
20 cs[i] = membench_alloc(arena);
21 assert(cs[i]);
22 }
23
24 // `n` times, free a random chunk and allocate another one in its
25 // place.
26 for (unsigned i = 0; i != n; ++i) {
27 unsigned pos = random() % k;
28 membench_free(arena, cs[pos]);
29 cs[pos] = membench_alloc(arena);
30 assert(cs[pos]);
31 }
32
33 // Free the chunks and the arena.
34 for (unsigned i = 0; i != k; ++i)
35 membench_free(arena, cs[i]);
36 membench_arena_free(arena);
37 free(cs);
38}
39
40void* benchmark_thread(void* user_data) {
41 (void) user_data;
42 benchmark();
43 return NULL;
44}
45
46int main(int argc, char** argv) {
47 int nthreads = 1;
48 int opt;
49 while ((opt = getopt(argc, argv, "n:k:j:")) != -1)
50 switch (opt) {
51 case 'n':
52 n = strtoul(optarg, NULL, 0);
53 break;
54 case 'k':
55 k = strtoul(optarg, NULL, 0);
56 break;
57 case 'j':
58 nthreads = strtol(optarg, NULL, 0);
59 break;
60 default:
61 fprintf(stderr, "Usage: ./membench [-n NOPS] [-k NALLOCS] [-j NTHREADS]\n");
62 exit(EXIT_FAILURE);
63 }
64
65 if (nthreads <= 1)
66 // Run the benchmark.
67 benchmark();
68 else {
69 // Run `nthreads` threads, each running the benchmark.
70 pthread_t threads[100];
71 assert(nthreads <= 100);
72 for (int i = 0; i != nthreads; ++i)
73 pthread_create(&threads[i], NULL, benchmark_thread, NULL);
74 for (int i = 0; i != nthreads; ++i)
75 pthread_join(threads[i], NULL);
76 }
77}
  
1#ifndef CS61_MEMBENCH_H
2#define CS61_MEMBENCH_H
3
4#define CHUNK_SIZE 8
5typedef struct chunk {
6 char contents[CHUNK_SIZE];
7} chunk;
8
9// `membench_arena` is an opaque type (users can't see what's in it).
10typedef struct membench_arena membench_arena;
11
12
13// membench_arena_new()
14// Allocate and initialize a new arena, returning the arena.
15membench_arena* membench_arena_new(void);
16
17
18// membench_alloc(arena)
19// Allocate and return a new chunk using the arena.
20chunk* membench_alloc(membench_arena* arena);
21
22
23// membench_free(arena)
24// Free a chunk `x` that was previously allocated from this arena.
25//
26// REQUIREMENT: `x` was previously returned by
27// `membench_alloc(arena)` for this arena, and not previously
28// freed, and `x != NULL`.
29void membench_free(membench_arena* arena, chunk* x);
30
31
32// membench_arena_free(arena)
33// Clean up the arena and free its memory.
34//
35// REQUIREMENT: Before `membench_arena_free(arena)` is called, all
36// chunks previously returned by `membench_alloc(arena)` have been
37// freed.
38void membench_arena_free(membench_arena* arena);
39
40#endif