… | |
… | |
170 | # define CORO_CLOCK_THREAD_CPUTIME_ID 3 |
170 | # define CORO_CLOCK_THREAD_CPUTIME_ID 3 |
171 | # endif |
171 | # endif |
172 | #endif |
172 | #endif |
173 | |
173 | |
174 | static double (*nvtime)(); /* so why doesn't it take void? */ |
174 | static double (*nvtime)(); /* so why doesn't it take void? */ |
|
|
175 | static void (*u2time)(pTHX_ UV ret[2]); |
175 | |
176 | |
176 | /* we hijack an hopefully unused CV flag for our purposes */ |
177 | /* we hijack an hopefully unused CV flag for our purposes */ |
177 | #define CVf_SLF 0x4000 |
178 | #define CVf_SLF 0x4000 |
178 | static OP *pp_slf (pTHX); |
179 | static OP *pp_slf (pTHX); |
179 | |
180 | |
… | |
… | |
206 | |
207 | |
207 | /* Coro::AnyEvent */ |
208 | /* Coro::AnyEvent */ |
208 | static SV *sv_activity; |
209 | static SV *sv_activity; |
209 | |
210 | |
210 | /* enable processtime/realtime profiling */ |
211 | /* enable processtime/realtime profiling */ |
211 | static char profile_times; |
212 | static char enable_times; |
212 | typedef U32 coro_ts[2]; |
213 | typedef U32 coro_ts[2]; |
|
|
214 | static coro_ts time_real, time_cpu; |
|
|
215 | static char times_valid; |
213 | |
216 | |
214 | static struct coro_cctx *cctx_first; |
217 | static struct coro_cctx *cctx_first; |
215 | static int cctx_count, cctx_idle; |
218 | static int cctx_count, cctx_idle; |
216 | |
219 | |
217 | enum { |
220 | enum { |
… | |
… | |
307 | |
310 | |
308 | /* on_enter/on_leave */ |
311 | /* on_enter/on_leave */ |
309 | AV *on_enter; |
312 | AV *on_enter; |
310 | AV *on_leave; |
313 | AV *on_leave; |
311 | |
314 | |
|
|
315 | /* times */ |
|
|
316 | coro_ts t_cpu, t_real; |
|
|
317 | |
312 | /* linked list */ |
318 | /* linked list */ |
313 | struct coro *next, *prev; |
319 | struct coro *next, *prev; |
314 | }; |
320 | }; |
315 | |
321 | |
316 | typedef struct coro *Coro__State; |
322 | typedef struct coro *Coro__State; |
… | |
… | |
380 | |
386 | |
381 | if (!cv) |
387 | if (!cv) |
382 | croak ("code reference expected"); |
388 | croak ("code reference expected"); |
383 | |
389 | |
384 | return cv; |
390 | return cv; |
|
|
391 | } |
|
|
392 | |
|
|
393 | INLINE void |
|
|
394 | coro_times_update () |
|
|
395 | { |
|
|
396 | #ifdef coro_clock_gettime |
|
|
397 | struct timespec ts; |
|
|
398 | |
|
|
399 | ts.tv_sec = ts.tv_nsec = 0; |
|
|
400 | coro_clock_gettime (CORO_CLOCK_THREAD_CPUTIME_ID, &ts); |
|
|
401 | time_cpu [0] = ts.tv_sec; time_cpu [1] = ts.tv_nsec; |
|
|
402 | |
|
|
403 | ts.tv_sec = ts.tv_nsec = 0; |
|
|
404 | coro_clock_gettime (CORO_CLOCK_MONOTONIC, &ts); |
|
|
405 | time_real [0] = ts.tv_sec; time_real [1] = ts.tv_nsec; |
|
|
406 | #else |
|
|
407 | UV tv[2]; |
|
|
408 | |
|
|
409 | u2time (aTHX_ &tv); |
|
|
410 | time_real [0] = tv [0]; |
|
|
411 | time_real [1] = tv [1] * 1000; |
|
|
412 | #endif |
|
|
413 | } |
|
|
414 | |
|
|
415 | INLINE void |
|
|
416 | coro_times_add (struct coro *c) |
|
|
417 | { |
|
|
418 | c->t_real [1] += time_real [1]; |
|
|
419 | if (c->t_real [1] > 1000000000) { c->t_real [1] -= 1000000000; ++c->t_real [0]; } |
|
|
420 | c->t_real [0] += time_real [0]; |
|
|
421 | |
|
|
422 | c->t_cpu [1] += time_cpu [1]; |
|
|
423 | if (c->t_cpu [1] > 1000000000) { c->t_cpu [1] -= 1000000000; ++c->t_cpu [0]; } |
|
|
424 | c->t_cpu [0] += time_cpu [0]; |
|
|
425 | } |
|
|
426 | |
|
|
427 | INLINE void |
|
|
428 | coro_times_sub (struct coro *c) |
|
|
429 | { |
|
|
430 | if (c->t_real [1] < time_real [1]) { c->t_real [1] += 1000000000; --c->t_real [0]; } |
|
|
431 | c->t_real [1] -= time_real [1]; |
|
|
432 | c->t_real [0] -= time_real [0]; |
|
|
433 | |
|
|
434 | if (c->t_cpu [1] < time_cpu [1]) { c->t_cpu [1] += 1000000000; --c->t_cpu [0]; } |
|
|
435 | c->t_cpu [1] -= time_cpu [1]; |
|
|
436 | c->t_cpu [0] -= time_cpu [0]; |
385 | } |
437 | } |
386 | |
438 | |
387 | /*****************************************************************************/ |
439 | /*****************************************************************************/ |
388 | /* magic glue */ |
440 | /* magic glue */ |
389 | |
441 | |
… | |
… | |
591 | } |
643 | } |
592 | |
644 | |
593 | slf_frame = c->slf_frame; |
645 | slf_frame = c->slf_frame; |
594 | CORO_THROW = c->except; |
646 | CORO_THROW = c->except; |
595 | |
647 | |
|
|
648 | if (expect_false (enable_times)) |
|
|
649 | { |
|
|
650 | if (expect_false (!times_valid)) |
|
|
651 | coro_times_update (); |
|
|
652 | |
|
|
653 | coro_times_sub (c); |
|
|
654 | } |
|
|
655 | |
596 | if (expect_false (c->on_enter)) |
656 | if (expect_false (c->on_enter)) |
597 | { |
657 | { |
598 | int i; |
658 | int i; |
599 | |
659 | |
600 | for (i = 0; i <= AvFILLp (c->on_enter); ++i) |
660 | for (i = 0; i <= AvFILLp (c->on_enter); ++i) |
… | |
… | |
609 | { |
669 | { |
610 | int i; |
670 | int i; |
611 | |
671 | |
612 | for (i = AvFILLp (c->on_leave); i >= 0; --i) |
672 | for (i = AvFILLp (c->on_leave); i >= 0; --i) |
613 | on_enterleave_call (aTHX_ AvARRAY (c->on_leave)[i]); |
673 | on_enterleave_call (aTHX_ AvARRAY (c->on_leave)[i]); |
|
|
674 | } |
|
|
675 | |
|
|
676 | times_valid = 0; |
|
|
677 | |
|
|
678 | if (expect_false (enable_times)) |
|
|
679 | { |
|
|
680 | coro_times_update (); times_valid = 1; |
|
|
681 | coro_times_add (c); |
614 | } |
682 | } |
615 | |
683 | |
616 | c->except = CORO_THROW; |
684 | c->except = CORO_THROW; |
617 | c->slf_frame = slf_frame; |
685 | c->slf_frame = slf_frame; |
618 | |
686 | |
… | |
… | |
982 | |
1050 | |
983 | PL_op = (OP *)&coro_setup_op; |
1051 | PL_op = (OP *)&coro_setup_op; |
984 | |
1052 | |
985 | /* copy throw, in case it was set before coro_setup */ |
1053 | /* copy throw, in case it was set before coro_setup */ |
986 | CORO_THROW = coro->except; |
1054 | CORO_THROW = coro->except; |
|
|
1055 | |
|
|
1056 | if (expect_false (enable_times)) |
|
|
1057 | { |
|
|
1058 | coro_times_update (); |
|
|
1059 | coro_times_sub (coro); |
|
|
1060 | } |
987 | } |
1061 | } |
988 | |
1062 | |
989 | static void |
1063 | static void |
990 | coro_unwind_stacks (pTHX) |
1064 | coro_unwind_stacks (pTHX) |
991 | { |
1065 | { |
… | |
… | |
2983 | |
3057 | |
2984 | if (!svp) croak ("Time::HiRes is required"); |
3058 | if (!svp) croak ("Time::HiRes is required"); |
2985 | if (!SvIOK (*svp)) croak ("Time::NVtime isn't a function pointer"); |
3059 | if (!SvIOK (*svp)) croak ("Time::NVtime isn't a function pointer"); |
2986 | |
3060 | |
2987 | nvtime = INT2PTR (double (*)(), SvIV (*svp)); |
3061 | nvtime = INT2PTR (double (*)(), SvIV (*svp)); |
|
|
3062 | |
|
|
3063 | svp = hv_fetch (PL_modglobal, "Time::U2time", 12, 0); |
|
|
3064 | u2time = INT2PTR (double (*)(), SvIV (*svp)); |
2988 | } |
3065 | } |
2989 | |
3066 | |
2990 | assert (("PRIO_NORMAL must be 0", !CORO_PRIO_NORMAL)); |
3067 | assert (("PRIO_NORMAL must be 0", !CORO_PRIO_NORMAL)); |
2991 | } |
3068 | } |
2992 | |
3069 | |
… | |
… | |
3266 | CODE: |
3343 | CODE: |
3267 | coro_state_destroy (aTHX_ self); |
3344 | coro_state_destroy (aTHX_ self); |
3268 | coro_call_on_destroy (aTHX_ self); /* actually only for Coro objects */ |
3345 | coro_call_on_destroy (aTHX_ self); /* actually only for Coro objects */ |
3269 | |
3346 | |
3270 | |
3347 | |
|
|
3348 | SV * |
|
|
3349 | enable_times (int enabled = enable_times) |
|
|
3350 | CODE: |
|
|
3351 | { |
|
|
3352 | RETVAL = boolSV (enable_times); |
|
|
3353 | |
|
|
3354 | if (enabled != enable_times) |
|
|
3355 | { |
|
|
3356 | enable_times = enabled; |
|
|
3357 | |
|
|
3358 | coro_times_update (); |
|
|
3359 | (enabled ? coro_times_sub : coro_times_add)(SvSTATE (coro_current)); |
|
|
3360 | } |
|
|
3361 | } |
|
|
3362 | OUTPUT: |
|
|
3363 | RETVAL |
|
|
3364 | |
|
|
3365 | void |
|
|
3366 | times (Coro::State self) |
|
|
3367 | PPCODE: |
|
|
3368 | { |
|
|
3369 | struct coro *current = SvSTATE (coro_current); |
|
|
3370 | |
|
|
3371 | if (expect_false (current == self)) |
|
|
3372 | { |
|
|
3373 | coro_times_update (); |
|
|
3374 | coro_times_add (SvSTATE (coro_current)); |
|
|
3375 | } |
|
|
3376 | |
|
|
3377 | EXTEND (SP, 2); |
|
|
3378 | PUSHs (sv_2mortal (newSVnv (self->t_real [0] + self->t_real [1] * 1e-9))); |
|
|
3379 | PUSHs (sv_2mortal (newSVnv (self->t_cpu [0] + self->t_cpu [1] * 1e-9))); |
|
|
3380 | |
|
|
3381 | if (expect_false (current == self)) |
|
|
3382 | coro_times_sub (SvSTATE (coro_current)); |
|
|
3383 | } |
|
|
3384 | |
3271 | MODULE = Coro::State PACKAGE = Coro |
3385 | MODULE = Coro::State PACKAGE = Coro |
3272 | |
3386 | |
3273 | BOOT: |
3387 | BOOT: |
3274 | { |
3388 | { |
3275 | sv_pool_rss = coro_get_sv (aTHX_ "Coro::POOL_RSS" , TRUE); |
3389 | sv_pool_rss = coro_get_sv (aTHX_ "Coro::POOL_RSS" , TRUE); |