Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/spesh/plan.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Adds a planned specialization, provided it doesn't already exist (this may
4
 * happen due to further data suggesting it being logged while it was being
5
 * produced). */
6
void add_planned(MVMThreadContext *tc, MVMSpeshPlan *plan, MVMSpeshPlannedKind kind,
7
                 MVMStaticFrame *sf, MVMSpeshStatsByCallsite *cs_stats,
8
                 MVMSpeshStatsType *type_tuple, MVMSpeshStatsByType **type_stats,
9
32.1k
                 MVMuint32 num_type_stats) {
10
32.1k
    MVMSpeshPlanned *p;
11
32.1k
    if (sf->body.bytecode_size > MVM_SPESH_MAX_BYTECODE_SIZE ||
12
32.1k
        MVM_spesh_arg_guard_exists(tc, sf->body.spesh->body.spesh_arg_guard, cs_stats->cs, type_tuple)) {
13
20.6k
        /* Clean up allocated memory.
14
20.6k
         * NB - the only caller is plan_for_cs, which means that we could do the
15
20.6k
         * allocations in here, except that we need the type tuple for the
16
20.6k
         * lookup already. So this is messy but it works. */
17
20.6k
        MVM_free(type_stats);
18
20.6k
        MVM_free(type_tuple);
19
20.6k
        return;
20
20.6k
    }
21
11.4k
    if (plan->num_planned == plan->alloc_planned) {
22
1.62k
        plan->alloc_planned += 16;
23
1.62k
        plan->planned = MVM_realloc(plan->planned,
24
1.62k
            plan->alloc_planned * sizeof(MVMSpeshPlanned));
25
1.62k
    }
26
11.4k
    p = &(plan->planned[plan->num_planned++]);
27
11.4k
    p->kind = kind;
28
11.4k
    p->sf = sf;
29
11.4k
    p->cs_stats = cs_stats;
30
11.4k
    p->type_tuple = type_tuple;
31
11.4k
    p->type_stats = type_stats;
32
11.4k
    p->num_type_stats = num_type_stats;
33
11.4k
    if (num_type_stats) {
34
10.6k
        MVMuint32 i;
35
10.6k
        p->max_depth = type_stats[0]->max_depth;
36
10.6k
        for (i = 1; i < num_type_stats; i++)
37
0
            if (type_stats[i]->max_depth > p->max_depth)
38
0
                p->max_depth = type_stats[i]->max_depth;
39
10.6k
    }
40
874
    else {
41
874
        p->max_depth = cs_stats->max_depth;
42
874
    }
43
11.4k
}
44
45
/* Makes a copy of an argument type tuple. */
46
MVMSpeshStatsType * copy_type_tuple(MVMThreadContext *tc, MVMCallsite *cs,
47
29.0k
        MVMSpeshStatsType *to_copy) {
48
29.0k
    size_t stats_size = cs->flag_count * sizeof(MVMSpeshStatsType);
49
29.0k
    MVMSpeshStatsType *result = MVM_malloc(stats_size);
50
29.0k
    memcpy(result, to_copy, stats_size);
51
29.0k
    return result;
52
29.0k
}
53
54
/* Considers the statistics of a given callsite + static frame pairing and
55
 * plans specializations to produce for it. */
56
void plan_for_cs(MVMThreadContext *tc, MVMSpeshPlan *plan, MVMStaticFrame *sf,
57
27.8k
                 MVMSpeshStatsByCallsite *by_cs) {
58
27.8k
    /* See if any types tuples are hot enough. */
59
27.8k
    MVMuint32 i;
60
27.8k
    MVMuint32 unaccounted_hits = by_cs->hits;
61
27.8k
    MVMuint32 unaccounted_osr_hits = by_cs->osr_hits;
62
127k
    for (i = 0; i < by_cs->num_by_type; i++) {
63
99.6k
        MVMSpeshStatsByType *by_type = &(by_cs->by_type[i]);
64
99.6k
        MVMuint32 hit_percent = by_cs->hits
65
99.6k
           ? (100 * by_type->hits) / by_cs->hits
66
0
           : 0;
67
99.6k
        MVMuint32 osr_hit_percent = by_cs->osr_hits
68
9.35k
            ? (100 * by_type->osr_hits) / by_cs->osr_hits
69
90.2k
            : 0;
70
99.6k
        if (by_cs->cs && (hit_percent >= MVM_SPESH_PLAN_TT_OBS_PERCENT ||
71
70.7k
                osr_hit_percent >= MVM_SPESH_PLAN_TT_OBS_PERCENT_OSR)) {
72
29.0k
            MVMSpeshStatsByType **evidence = MVM_malloc(sizeof(MVMSpeshStatsByType *));
73
29.0k
            evidence[0] = by_type;
74
29.0k
            add_planned(tc, plan, MVM_SPESH_PLANNED_OBSERVED_TYPES, sf, by_cs,
75
29.0k
                copy_type_tuple(tc, by_cs->cs, by_type->arg_types), evidence, 1);
76
29.0k
            unaccounted_hits -= by_type->hits;
77
29.0k
            unaccounted_osr_hits -= by_type->osr_hits;
78
29.0k
        }
79
70.5k
        else {
80
70.5k
            /* TODO derived specialization planning */
81
70.5k
        }
82
99.6k
    }
83
27.8k
84
27.8k
    /* If there are enough unaccounted for hits by type specializations, then
85
27.8k
     * plan a certain specialization. */
86
27.8k
    if (unaccounted_hits && unaccounted_hits >= MVM_spesh_threshold(tc, sf) ||
87
24.8k
            unaccounted_osr_hits >= MVM_SPESH_PLAN_CS_MIN_OSR)
88
3.17k
        add_planned(tc, plan, MVM_SPESH_PLANNED_CERTAIN, sf, by_cs, NULL, NULL, 0);
89
27.8k
}
90
91
/* Considers the statistics of a given static frame and plans specializtions
92
 * to produce for it. */
93
299k
void plan_for_sf(MVMThreadContext *tc, MVMSpeshPlan *plan, MVMStaticFrame *sf) {
94
299k
    MVMSpeshStats *ss = sf->body.spesh->body.spesh_stats;
95
299k
    MVMuint32 threshold = MVM_spesh_threshold(tc, sf);
96
299k
    if (ss->hits >= threshold || ss->osr_hits >= MVM_SPESH_PLAN_SF_MIN_OSR) {
97
27.8k
        /* The frame is hot enough; look through its callsites to see if any
98
27.8k
         * of those are. */
99
27.8k
        MVMuint32 i;
100
78.5k
        for (i = 0; i < ss->num_by_callsite; i++) {
101
50.7k
            MVMSpeshStatsByCallsite *by_cs = &(ss->by_callsite[i]);
102
50.7k
            if (by_cs->hits >= threshold || by_cs->osr_hits >= MVM_SPESH_PLAN_CS_MIN_OSR)
103
27.8k
                plan_for_cs(tc, plan, sf, by_cs);
104
50.7k
        }
105
27.8k
    }
106
299k
}
107
108
/* Sorts the plan in descending order of maximum call depth. */
109
21.4k
void sort_plan(MVMThreadContext *tc, MVMSpeshPlanned *planned, MVMuint32 n) {
110
21.4k
    if (n >= 2) {
111
9.91k
        MVMSpeshPlanned pivot = planned[n / 2];
112
9.91k
        MVMuint32 i, j;
113
19.4k
        for (i = 0, j = n - 1; ; i++, j--) {
114
19.4k
            MVMSpeshPlanned temp;
115
29.3k
            while (planned[i].max_depth > pivot.max_depth)
116
9.89k
                i++;
117
26.1k
            while (planned[j].max_depth < pivot.max_depth)
118
6.71k
                j--;
119
19.4k
            if (i >= j)
120
9.91k
                break;
121
9.50k
            temp = planned[i];
122
9.50k
            planned[i] = planned[j];
123
9.50k
            planned[j] = temp;
124
9.50k
        }
125
9.91k
        sort_plan(tc, planned, i);
126
9.91k
        sort_plan(tc, planned + i, n - i);
127
9.91k
    }
128
21.4k
}
129
130
/* Forms a specialization plan from considering all frames whose statics have
131
 * changed. */
132
1.58k
MVMSpeshPlan * MVM_spesh_plan(MVMThreadContext *tc, MVMObject *updated_static_frames) {
133
1.58k
    MVMSpeshPlan *plan = MVM_calloc(1, sizeof(MVMSpeshPlan));
134
1.58k
    MVMint64 updated = MVM_repr_elems(tc, updated_static_frames);
135
1.58k
    MVMint64 i;
136
1.58k
#if MVM_GC_DEBUG
137
    tc->in_spesh = 1;
138
#endif
139
301k
    for (i = 0; i < updated; i++) {
140
299k
        MVMObject *sf = MVM_repr_at_pos_o(tc, updated_static_frames, i);
141
299k
        plan_for_sf(tc, plan, (MVMStaticFrame *)sf);
142
299k
    }
143
1.58k
    sort_plan(tc, plan->planned, plan->num_planned);
144
1.58k
#if MVM_GC_DEBUG
145
    tc->in_spesh = 0;
146
#endif
147
1.58k
    return plan;
148
1.58k
}
149
150
/* Marks garbage-collectable objects held in the spesh plan. */
151
338
void MVM_spesh_plan_gc_mark(MVMThreadContext *tc, MVMSpeshPlan *plan, MVMGCWorklist *worklist) {
152
338
    MVMuint32 i;
153
338
    if (!plan)
154
260
        return;
155
986
    for (i = 0; i < plan->num_planned; i++) {
156
908
        MVMSpeshPlanned *p = &(plan->planned[i]);
157
908
        MVM_gc_worklist_add(tc, worklist, &(p->sf));
158
908
        if (p->type_tuple) {
159
828
            MVMCallsite *cs = p->cs_stats->cs;
160
828
            MVMuint32 j;
161
2.49k
            for (j = 0; j < cs->flag_count; j++) {
162
1.67k
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_OBJ) {
163
1.48k
                    MVM_gc_worklist_add(tc, worklist, &(p->type_tuple[j].type));
164
1.48k
                    MVM_gc_worklist_add(tc, worklist, &(p->type_tuple[j].decont_type));
165
1.48k
                }
166
1.67k
            }
167
828
        }
168
908
    }
169
78
}
170
171
0
void MVM_spesh_plan_gc_describe(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSpeshPlan *plan) {
172
0
    MVMuint32 i;
173
0
    if (!plan)
174
0
        return;
175
0
    for (i = 0; i < plan->num_planned; i++) {
176
0
        MVMSpeshPlanned *p = &(plan->planned[i]);
177
0
        MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
178
0
            (MVMCollectable*)(p->sf), "staticframe");
179
0
        if (p->type_tuple) {
180
0
            MVMCallsite *cs = p->cs_stats->cs;
181
0
            MVMuint32 j;
182
0
            for (j = 0; j < cs->flag_count; j++) {
183
0
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_OBJ) {
184
0
                    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
185
0
                        (MVMCollectable*)(p->type_tuple[j].type), "argument type");
186
0
                    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
187
0
                        (MVMCollectable*)(p->type_tuple[j].decont_type), "argument decont type");
188
0
                }
189
0
            }
190
0
        }
191
0
    }
192
0
}
193
194
/* Frees all memory associated with a specialization plan. */
195
1.47k
void MVM_spesh_plan_destroy(MVMThreadContext *tc, MVMSpeshPlan *plan) {
196
1.47k
    MVMuint32 i;
197
12.0k
    for (i = 0; i < plan->num_planned; i++) {
198
10.5k
        MVM_free(plan->planned[i].type_stats);
199
10.5k
        MVM_free(plan->planned[i].type_tuple);
200
10.5k
    }
201
1.47k
    MVM_free(plan->planned);
202
1.47k
    MVM_free(plan);
203
1.47k
}