Companion code · Chapter 8

Growable Arrays and Linked Lists: The Cost of Growth

3 files. About this chapter.

Download ch08.zip

ch08/node_spacing.c15 lines
/* Chapter 8 companion: how far apart two 16-byte blocks land on glibc.
 * malloc_usable_size is a glibc extension, so build with -std=gnu17. */
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char *a = malloc(16), *b = malloc(16);
    if (a == NULL || b == NULL) return 1;
    printf("usable %zu bytes, blocks %td bytes apart\n",
           malloc_usable_size(a), b - a);
    free(a);
    free(b);
    return 0;
}
ch08/realloc_moves.c40 lines
/* Chapter 8 companion: push n readings with realloc-based growth,
 * +1 (policy "plus1") or doubling ("double"); report the time and how
 * many times realloc returned a different address (a move).
 * Usage: ./realloc_moves plus1|double n */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

struct reading { uint32_t sensor_id; int64_t time_s; double value; uint8_t flags; };

static double seconds(void) {
    struct timespec t;
    timespec_get(&t, TIME_UTC);
    return (double)t.tv_sec + (double)t.tv_nsec / 1e9;
}

int main(int argc, char *argv[]) {
    if (argc != 3) { fprintf(stderr, "usage: %s plus1|double n\n", argv[0]); return 2; }
    int doubling = strcmp(argv[1], "double") == 0;
    size_t n = strtoul(argv[2], NULL, 10);
    struct reading *data = NULL;
    size_t size = 0, cap = 0, moves = 0;
    double start = seconds();
    for (size_t i = 0; i < n; i++) {
        if (size == cap) {
            size_t new_cap = doubling ? (cap ? 2 * cap : 1) : cap + 1;
            struct reading *tmp = realloc(data, new_cap * sizeof *tmp);
            if (tmp == NULL) { free(data); return 1; }
            if (tmp != data) moves++;
            data = tmp;
            cap = new_cap;
        }
        data[size++] = (struct reading){1001, (int64_t)i * 60, 20.0, 1};
    }
    printf("%s n=%zu time=%.4f s moves=%zu\n", argv[1], n, seconds() - start, moves);
    free(data);
    return 0;
}
ch08/traverse_time.c57 lines
/* Chapter 8 companion: sum 1,000,000 values from an array, from a list
 * whose nodes are linked in allocation order, and from the same nodes
 * linked in shuffled order. Best of five runs each. Build with -O2. */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct node { double value; struct node *next; };

static double seconds(void) {
    struct timespec t;
    timespec_get(&t, TIME_UTC);
    return (double)t.tv_sec + (double)t.tv_nsec / 1e9;
}

int main(void) {
    const size_t n = 1000000;
    double *a = malloc(n * sizeof *a);
    struct node **nodes = malloc(n * sizeof *nodes);
    size_t *order = malloc(n * sizeof *order);
    if (a == NULL || nodes == NULL || order == NULL) return 1;
    for (size_t i = 0; i < n; i++) {
        a[i] = (double)i;
        nodes[i] = malloc(sizeof **nodes);
        if (nodes[i] == NULL) return 1;
        nodes[i]->value = (double)i;
        order[i] = i;
    }
    for (int shuffled = 0; shuffled <= 1; shuffled++) {
        if (shuffled) {
            srand(1);
            for (size_t i = n - 1; i > 0; i--) {
                size_t j = ((size_t)rand() * ((size_t)RAND_MAX + 1) + (size_t)rand()) % (i + 1);
                size_t t = order[i]; order[i] = order[j]; order[j] = t;
            }
        }
        for (size_t i = 0; i < n; i++)
            nodes[order[i]]->next = (i + 1 < n) ? nodes[order[i + 1]] : NULL;
        struct node *head = nodes[order[0]];
        double best_a = 1e9, best_l = 1e9, check = 0;
        for (int r = 0; r < 5; r++) {
            double t0 = seconds(), s = 0;
            for (size_t i = 0; i < n; i++) s += a[i];
            double t1 = seconds();
            for (struct node *p = head; p != NULL; p = p->next) s += p->value;
            double t2 = seconds();
            check += s;
            if (t1 - t0 < best_a) best_a = t1 - t0;
            if (t2 - t1 < best_l) best_l = t2 - t1;
        }
        printf("%s: array %.1f ms, list %.1f ms (checksum %g)\n",
               shuffled ? "shuffled" : "in order", best_a * 1e3, best_l * 1e3, check);
    }
    for (size_t i = 0; i < n; i++) free(nodes[i]);
    free(nodes); free(order); free(a);
    return 0;
}