aboutsummaryrefslogtreecommitdiff
path: root/src/stack_report.cpp
blob: 3a0abd6cef5371580ba7ad8f8bbcfda5c5d7fb28 (plain)
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
/*
 * Copyright (c) 2019 Andrew Kelley
 *
 * This file is part of zig, which is MIT licensed.
 * See http://opensource.org/licenses/MIT
 */

#include "stack_report.hpp"

static void tree_print(FILE *f, ZigType *ty, size_t indent);

static void pretty_print_bytes(FILE *f, double n) {
    if (n > 1024.0 * 1024.0 * 1024.0) {
        fprintf(f, "%.02f GiB", n / 1024.0 / 1024.0 / 1024.0);
        return;
    }
    if (n > 1024.0 * 1024.0) {
        fprintf(f, "%.02f MiB", n / 1024.0 / 1024.0);
        return;
    }
    if (n > 1024.0) {
        fprintf(f, "%.02f KiB", n / 1024.0);
        return;
    }
    fprintf(f, "%.02f bytes", n );
    return;
}

static int compare_type_abi_sizes_desc(const void *a, const void *b) {
    uint64_t size_a = (*(ZigType * const*)(a))->abi_size;
    uint64_t size_b = (*(ZigType * const*)(b))->abi_size;
    if (size_a > size_b)
        return -1;
    if (size_a < size_b)
        return 1;
    return 0;
}

static void start_child(FILE *f, size_t indent) {
    fprintf(f, "\n");
    for (size_t i = 0; i < indent; i += 1) {
        fprintf(f, " ");
    }
}

static void start_peer(FILE *f, size_t indent) {
    fprintf(f, ",\n");
    for (size_t i = 0; i < indent; i += 1) {
        fprintf(f, " ");
    }
}

static void tree_print_struct(FILE *f, ZigType *struct_type, size_t indent) {
    ZigList<ZigType *> children = {};
    uint64_t sum_from_fields = 0;
    for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
        TypeStructField *field = &struct_type->data.structure.fields[i];
        children.append(field->type_entry);
        sum_from_fields += field->type_entry->abi_size;
    }
    qsort(children.items, children.length, sizeof(ZigType *), compare_type_abi_sizes_desc);

    start_peer(f, indent);
    fprintf(f, "\"padding\": \"%" ZIG_PRI_u64 "\"", struct_type->abi_size - sum_from_fields);

    start_peer(f, indent);
    fprintf(f, "\"fields\": [");

    for (size_t i = 0; i < children.length; i += 1) {
        if (i == 0) {
            start_child(f, indent + 1);
        } else {
            start_peer(f, indent + 1);
        }
        fprintf(f, "{");

        ZigType *child_type = children.at(i);
        tree_print(f, child_type, indent + 2);

        start_child(f, indent + 1);
        fprintf(f, "}");
    }

    start_child(f, indent);
    fprintf(f, "]");
}

static void tree_print(FILE *f, ZigType *ty, size_t indent) {
    start_child(f, indent);
    fprintf(f, "\"type\": \"%s\"", buf_ptr(&ty->name));

    start_peer(f, indent);
    fprintf(f, "\"sizef\": \"");
    pretty_print_bytes(f, ty->abi_size);
    fprintf(f, "\"");

    start_peer(f, indent);
    fprintf(f, "\"size\": \"%" ZIG_PRI_u64 "\"", ty->abi_size);

    switch (ty->id) {
        case ZigTypeIdFnFrame:
            return tree_print_struct(f, ty->data.frame.locals_struct, indent);
        case ZigTypeIdStruct:
            return tree_print_struct(f, ty, indent);
        default:
            start_child(f, indent);
            return;
    }
}

void zig_print_stack_report(CodeGen *g, FILE *f) {
    if (g->largest_frame_fn == nullptr) {
        fprintf(f, "{\"error\": \"No async function frames in entire compilation.\"}\n");
        return;
    }
    fprintf(f, "{");
    tree_print(f, g->largest_frame_fn->frame_type, 1);

    start_child(f, 0);
    fprintf(f, "}\n");
}