File Coverage

lib/Future/AsyncAwait/Metrics.xs
Criterion Covered Total %
statement 67 68 98.5
branch 41 86 47.6
condition n/a
subroutine n/a
pod n/a
total 108 154 70.1


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2022 -- leonerd@leonerd.org.uk
5             */
6             #include "EXTERN.h"
7             #include "perl.h"
8             #include "XSUB.h"
9              
10             #include "AsyncAwait.h"
11              
12 10           static SV *S_call_metrics_method(pTHX_ U8 gimme, SV *metrics, const char *method, SV *arg1, SV *arg2)
13             {
14 10           dSP;
15 10           ENTER;
16 10           SAVETMPS;
17              
18 10 50         EXTEND(SP, 3);
19 10 50         PUSHMARK(SP);
20 10           PUSHs(metrics);
21 10           mPUSHs(arg1);
22 10 100         if(arg2)
23 9           mPUSHs(arg2);
24 10           PUTBACK;
25              
26 10           call_method(method, gimme);
27              
28             SV *ret;
29              
30 10 100         if(gimme > G_VOID) {
31 1           SPAGAIN;
32 1           ret = POPs;
33             SvREFCNT_inc(ret);
34 1           PUTBACK;
35             }
36              
37 10 50         FREETMPS;
38 10           LEAVE;
39              
40 10           return ret;
41             }
42              
43             #define call_metrics_method_pvn(gimme, metrics, method, pv, len) \
44             S_call_metrics_method(aTHX_ gimme, metrics, method, newSVpvn(pv, len), NULL)
45             #define call_metrics_method_pvn_iv(gimme, metrics, method, pv, len, iv) \
46             S_call_metrics_method(aTHX_ gimme, metrics, method, newSVpvn(pv, len), newSViv(iv))
47              
48             struct FAAMetricsState
49             {
50             SV *metrics;
51              
52             bool use_batch_mode;
53              
54             UV states_created_counter;
55             UV suspends_counter;
56             UV resumes_counter;
57             UV states_destroyed_counter;
58              
59             IV current_states_gauge;
60             IV current_subs_gauge;
61             };
62              
63             XS_INTERNAL(flush_metrics);
64              
65 9           static struct FAAMetricsState *S_get_state(pTHX)
66             {
67             struct FAAMetricsState *state;
68              
69 9           SV **svp = hv_fetchs(PL_modglobal, "Future::AsyncAwait::Metrics/state", GV_ADD);
70 9 100         if(SvOK(*svp))
    50          
    50          
71 8 50         state = INT2PTR(struct FAAMetricsState *, SvUV(*svp));
72             else {
73 1           Newx(state, 1, struct FAAMetricsState);
74 1           sv_setuv(*svp, PTR2UV(state));
75              
76 1           state->metrics = get_sv("Future::AsyncAwait::Metrics::metrics", 0);
77              
78 1           SV *r = S_call_metrics_method(aTHX_ G_SCALAR, state->metrics,
79             "add_batch_mode_callback",
80 1           newRV_noinc((SV *)newXS_flags("flush_metrics", flush_metrics, __FILE__, NULL, 0)),
81             NULL
82             );
83              
84 1 50         if(r && SvTRUE(r)) {
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
85 1           state->use_batch_mode = TRUE;
86              
87 1           state->states_created_counter = 0;
88 1           state->suspends_counter = 0;
89 1           state->resumes_counter = 0;
90 1           state->states_destroyed_counter = 0;
91              
92 1           state->current_states_gauge = 0;
93 1           state->current_subs_gauge = 0;
94             }
95             else
96 0           state->use_batch_mode = FALSE;
97             }
98              
99 9           return state;
100             }
101             #define get_state() S_get_state(aTHX)
102              
103 3           XS_INTERNAL(flush_metrics)
104             {
105 3           struct FAAMetricsState *state = get_state();
106              
107             #define FLUSH_COUNTER(name) \
108             if(state->name##_counter) { \
109             call_metrics_method_pvn_iv(G_VOID, state->metrics, "inc_counter_by", \
110             "" #name "", sizeof(#name)-1, state->name##_counter); \
111             state->name##_counter = 0; \
112             }
113              
114 3 100         FLUSH_COUNTER(states_created);
115 3 100         FLUSH_COUNTER(suspends);
116 3 100         FLUSH_COUNTER(resumes);
117 3 100         FLUSH_COUNTER(states_destroyed);
118              
119             #define FLUSH_GAUGE(name) \
120             if(state->name##_gauge) { \
121             call_metrics_method_pvn_iv(G_VOID, state->metrics, "inc_gauge_by", \
122             "" #name "", sizeof(#name)-1, state->name##_gauge); \
123             state->name##_gauge = 0; \
124             }
125              
126 3 100         FLUSH_GAUGE(current_states);
127 3 100         FLUSH_GAUGE(current_subs);
128 3           }
129              
130             #define INC_COUNTER(name) \
131             if(state->use_batch_mode) \
132             state->name##_counter++; \
133             else \
134             call_metrics_method_pvn(G_VOID, state->metrics, "inc_counter", "" #name "", sizeof(#name)-1)
135              
136             #define INC_GAUGE(name) \
137             if(state->use_batch_mode) \
138             state->name##_gauge++; \
139             else \
140             call_metrics_method_pvn(G_VOID, state->metrics, "inc_gauge", "" #name "", sizeof(#name)-1)
141             #define DEC_GAUGE(name) \
142             if(state->use_batch_mode) \
143             state->name##_gauge--; \
144             else \
145             call_metrics_method_pvn(G_VOID, state->metrics, "dec_gauge", "" #name "", sizeof(#name)-1)
146              
147 1           static void hook_post_cvcopy(pTHX_ CV *runcv, CV *cv, HV *modhookdata, void *hookdata)
148             {
149 1           struct FAAMetricsState *state = get_state();
150              
151 1 50         INC_COUNTER(states_created);
152 1 50         INC_GAUGE(current_states);
153 1           }
154              
155 2           static void hook_post_suspend(pTHX_ CV *cv, HV *modhookdata, void *hookdata)
156             {
157 2           struct FAAMetricsState *state = get_state();
158              
159 2 50         INC_COUNTER(suspends);
160 2 50         INC_GAUGE(current_subs);
161 2           }
162              
163 2           static void hook_pre_resume(pTHX_ CV *cv, HV *modhookdata, void *hookdata)
164             {
165 2           struct FAAMetricsState *state = get_state();
166              
167 2 50         INC_COUNTER(resumes);
168 2 50         DEC_GAUGE(current_subs);
169 2           }
170              
171 1           static void hook_free(pTHX_ CV *cv, HV *modhookdata, void *hookdata)
172             {
173 1           struct FAAMetricsState *state = get_state();
174              
175 1 50         INC_COUNTER(states_destroyed);
176 1 50         DEC_GAUGE(current_states);
177 1           }
178              
179             static const struct AsyncAwaitHookFuncs hooks = {
180             .post_cv_copy = &hook_post_cvcopy,
181             .post_suspend = &hook_post_suspend,
182             .pre_resume = &hook_pre_resume,
183             .free = &hook_free,
184             };
185              
186             MODULE = Future::AsyncAwait::Metrics PACKAGE = Future::AsyncAwait::Metrics
187              
188             BOOT:
189 2           boot_future_asyncawait(0.60);
190              
191             register_future_asyncawait_hook(&hooks, NULL);