Skip to content

Commit 66ea413

Browse files
committed
Merge branch 'sb/_se-back-port/timerate' into sb/trunk-rewrite-clock-in-c
2 parents 65e229a + 07d3724 commit 66ea413

File tree

2 files changed

+197
-24
lines changed

2 files changed

+197
-24
lines changed

generic/tclBasic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ static const CmdInfo builtInCmds[] = {
286286
{"source", Tcl_SourceObjCmd, NULL, TclNRSourceObjCmd, 0},
287287
{"tell", Tcl_TellObjCmd, NULL, NULL, CMD_IS_SAFE},
288288
{"time", Tcl_TimeObjCmd, NULL, NULL, CMD_IS_SAFE},
289-
{"timerate", Tcl_TimeRateObjCmd, NULL, NULL, CMD_IS_SAFE},
289+
{"timerate", Tcl_TimeRateObjCmd, NULL, NULL, CMD_IS_SAFE},
290290
{"unload", Tcl_UnloadObjCmd, NULL, NULL, 0},
291291
{"update", Tcl_UpdateObjCmd, NULL, NULL, CMD_IS_SAFE},
292292
{"vwait", Tcl_VwaitObjCmd, NULL, NULL, CMD_IS_SAFE},

generic/tclCmdMZ.c

Lines changed: 196 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "tclInt.h"
20+
#include "tclCompile.h"
2021
#include "tclRegexp.h"
2122
#include "tclStringTrim.h"
2223

@@ -4050,43 +4051,192 @@ Tcl_TimeRateObjCmd(
40504051
int objc, /* Number of arguments. */
40514052
Tcl_Obj *const objv[]) /* Argument objects. */
40524053
{
4054+
static
4055+
double measureOverhead = 0; /* global measure-overhead */
4056+
double overhead = -1; /* given measure-overhead */
40534057
register Tcl_Obj *objPtr;
4054-
register int result;
4058+
register int result, i;
4059+
Tcl_Obj *calibrate = NULL, *direct = NULL;
40554060
Tcl_WideInt count = 0; /* Holds repetition count */
4056-
Tcl_WideInt maxms; /* Maximal running time (in milliseconds) */
4061+
Tcl_WideInt maxms = -0x7FFFFFFFFFFFFFFFL;
4062+
/* Maximal running time (in milliseconds) */
40574063
Tcl_WideInt threshold = 1; /* Current threshold for check time (faster
4058-
* repeat count without time check) */
4064+
* repeat count without time check) */
40594065
Tcl_WideInt maxIterTm = 1; /* Max time of some iteration as max threshold
4060-
* additionally avoid divide to zero (never < 1) */
4066+
* additionally avoid divide to zero (never < 1) */
40614067
register Tcl_WideInt start, middle, stop;
40624068
#ifndef TCL_WIDE_CLICKS
40634069
Tcl_Time now;
40644070
#endif
40654071

4066-
if (objc == 2) {
4067-
maxms = 1000;
4068-
} else if (objc == 3) {
4069-
result = TclGetWideIntFromObj(interp, objv[2], &maxms);
4072+
static const char *const options[] = {
4073+
"-direct", "-overhead", "-calibrate", "--", NULL
4074+
};
4075+
enum options {
4076+
TMRT_EV_DIRECT, TMRT_OVERHEAD, TMRT_CALIBRATE, TMRT_LAST
4077+
};
4078+
4079+
NRE_callback *rootPtr;
4080+
ByteCode *codePtr = NULL;
4081+
4082+
for (i = 1; i < objc - 1; i++) {
4083+
int index;
4084+
if (Tcl_GetIndexFromObj(NULL, objv[i], options, "option", TCL_EXACT,
4085+
&index) != TCL_OK) {
4086+
break;
4087+
}
4088+
if (index == TMRT_LAST) {
4089+
i++;
4090+
break;
4091+
}
4092+
switch ((enum options) index) {
4093+
case TMRT_EV_DIRECT:
4094+
direct = objv[i];
4095+
break;
4096+
case TMRT_OVERHEAD:
4097+
if (++i >= objc - 1) {
4098+
goto usage;
4099+
}
4100+
if (Tcl_GetDoubleFromObj(interp, objv[i], &overhead) != TCL_OK) {
4101+
return TCL_ERROR;
4102+
}
4103+
break;
4104+
case TMRT_CALIBRATE:
4105+
calibrate = objv[i];
4106+
break;
4107+
}
4108+
}
4109+
4110+
if (i >= objc || i < objc-2) {
4111+
usage:
4112+
Tcl_WrongNumArgs(interp, 1, objv, "?-direct? ?-calibrate? ?-overhead double? command ?time?");
4113+
return TCL_ERROR;
4114+
}
4115+
objPtr = objv[i++];
4116+
if (i < objc) {
4117+
result = TclGetWideIntFromObj(interp, objv[i], &maxms);
40704118
if (result != TCL_OK) {
40714119
return result;
40724120
}
4073-
} else {
4074-
Tcl_WrongNumArgs(interp, 1, objv, "command ?time?");
4075-
return TCL_ERROR;
40764121
}
40774122

4078-
objPtr = objv[1];
4123+
/* if calibrate */
4124+
if (calibrate) {
4125+
4126+
/* if no time specified for the calibration */
4127+
if (maxms == -0x7FFFFFFFFFFFFFFFL) {
4128+
Tcl_Obj *clobjv[6];
4129+
Tcl_WideInt maxCalTime = 5000;
4130+
double lastMeasureOverhead = measureOverhead;
4131+
4132+
clobjv[0] = objv[0];
4133+
i = 1;
4134+
if (direct) {
4135+
clobjv[i++] = direct;
4136+
}
4137+
clobjv[i++] = objPtr;
4138+
4139+
/* reset last measurement overhead */
4140+
measureOverhead = (double)0;
4141+
4142+
/* self-call with 100 milliseconds to warm-up,
4143+
* before entering the calibration cycle */
4144+
TclNewLongObj(clobjv[i], 100);
4145+
Tcl_IncrRefCount(clobjv[i]);
4146+
result = Tcl_TimeRateObjCmd(dummy, interp, i+1, clobjv);
4147+
Tcl_DecrRefCount(clobjv[i]);
4148+
if (result != TCL_OK) {
4149+
return result;
4150+
}
4151+
4152+
i--;
4153+
clobjv[i++] = calibrate;
4154+
clobjv[i++] = objPtr;
4155+
4156+
/* set last measurement overhead to max */
4157+
measureOverhead = (double)0x7FFFFFFFFFFFFFFFL;
4158+
4159+
/* calibration cycle until it'll be preciser */
4160+
maxms = -1000;
4161+
do {
4162+
lastMeasureOverhead = measureOverhead;
4163+
TclNewLongObj(clobjv[i], (int)maxms);
4164+
Tcl_IncrRefCount(clobjv[i]);
4165+
result = Tcl_TimeRateObjCmd(dummy, interp, i+1, clobjv);
4166+
Tcl_DecrRefCount(clobjv[i]);
4167+
if (result != TCL_OK) {
4168+
return result;
4169+
}
4170+
maxCalTime += maxms;
4171+
/* increase maxms for preciser calibration */
4172+
maxms -= (-maxms / 4);
4173+
/* as long as new value more as 0.05% better */
4174+
} while ( (measureOverhead >= lastMeasureOverhead
4175+
|| measureOverhead / lastMeasureOverhead <= 0.9995)
4176+
&& maxCalTime > 0
4177+
);
4178+
4179+
return result;
4180+
}
4181+
if (maxms == 0) {
4182+
/* reset last measurement overhead */
4183+
measureOverhead = 0;
4184+
Tcl_SetObjResult(interp, Tcl_NewLongObj(0));
4185+
return TCL_OK;
4186+
}
4187+
4188+
/* if time is negative - make current overhead more precise */
4189+
if (maxms > 0) {
4190+
/* set last measurement overhead to max */
4191+
measureOverhead = (double)0x7FFFFFFFFFFFFFFFL;
4192+
} else {
4193+
maxms = -maxms;
4194+
}
4195+
4196+
}
4197+
4198+
if (maxms == -0x7FFFFFFFFFFFFFFFL) {
4199+
maxms = 1000;
4200+
}
4201+
if (overhead == -1) {
4202+
overhead = measureOverhead;
4203+
}
4204+
4205+
/* be sure that resetting of result will not smudge the further measurement */
4206+
Tcl_ResetResult(interp);
4207+
4208+
/* compile object */
4209+
if (!direct) {
4210+
if (TclInterpReady(interp) != TCL_OK) {
4211+
return TCL_ERROR;
4212+
}
4213+
codePtr = TclCompileObj(interp, objPtr, NULL, 0);
4214+
}
4215+
4216+
/* get start and stop time */
40794217
#ifndef TCL_WIDE_CLICKS
40804218
Tcl_GetTime(&now);
40814219
start = now.sec; start *= 1000000; start += now.usec;
40824220
#else
40834221
start = TclpGetWideClicks();
40844222
#endif
4223+
4224+
/* start measurement */
40854225
stop = start + maxms * 1000;
40864226
middle = start;
40874227
while (1) {
4228+
/* eval single iteration */
40884229
count++;
4089-
result = TclEvalObjEx(interp, objPtr, 0, NULL, 0);
4230+
4231+
if (!direct) {
4232+
/* precompiled */
4233+
rootPtr = TOP_CB(interp);
4234+
result = TclNRExecuteByteCode(interp, codePtr);
4235+
result = TclNRRunCallbacks(interp, result, rootPtr);
4236+
} else {
4237+
/* eval */
4238+
result = TclEvalObjEx(interp, objPtr, 0, NULL, 0);
4239+
}
40904240
if (result != TCL_OK) {
40914241
return result;
40924242
}
@@ -4110,18 +4260,40 @@ Tcl_TimeRateObjCmd(
41104260
maxIterTm = threshold;
41114261
}
41124262
/* as relation between remaining time and time since last check */
4113-
threshold = ((stop - middle) / maxIterTm) / 2;
4114-
if (threshold > 5000) { /* fix for too large threshold */
4115-
threshold = 5000;
4263+
threshold = ((stop - middle) / maxIterTm) / 4;
4264+
if (threshold > 100000) { /* fix for too large threshold */
4265+
threshold = 100000;
41164266
}
41174267
}
41184268

4119-
if (1) {
4120-
Tcl_Obj *objs[6];
4269+
{
4270+
Tcl_Obj *objarr[8], **objs = objarr;
41214271
Tcl_WideInt val;
41224272
const char *fmt;
41234273

41244274
middle -= start; /* execution time in microsecs */
4275+
4276+
/* if not calibrate */
4277+
if (!calibrate) {
4278+
/* minimize influence of measurement overhead */
4279+
if (overhead > 0) {
4280+
Tcl_WideInt curOverhead = overhead * count;
4281+
if (middle > curOverhead) {
4282+
middle -= curOverhead;
4283+
} else {
4284+
middle = 1;
4285+
}
4286+
}
4287+
} else {
4288+
/* calibration - obtaining new measurement overhead */
4289+
if (measureOverhead > (double)middle / count) {
4290+
measureOverhead = (double)middle / count;
4291+
}
4292+
objs[0] = Tcl_NewDoubleObj(measureOverhead);
4293+
TclNewLiteralStringObj(objs[1], "\xC2\xB5s/#-overhead,"); /* mics */
4294+
objs += 2;
4295+
}
4296+
41254297
val = middle / count; /* microsecs per iteration */
41264298
if (val >= 1000000) {
41274299
objs[0] = Tcl_NewWideIntObj(val);
@@ -4130,20 +4302,20 @@ Tcl_TimeRateObjCmd(
41304302
if (val < 100) { fmt = "%.4f"; } else
41314303
if (val < 1000) { fmt = "%.3f"; } else
41324304
if (val < 10000) { fmt = "%.2f"; } else
4133-
{ fmt = "%.1f"; };
4305+
{ fmt = "%.1f"; };
41344306
objs[0] = Tcl_ObjPrintf(fmt, ((double)middle)/count);
41354307
}
41364308

41374309
objs[2] = Tcl_NewWideIntObj(count); /* iterations */
41384310

41394311
/* calculate speed as rate (count) per sec */
41404312
if (!middle) middle++; /* +1 ms, just to avoid divide by zero */
4141-
if (count < (0X7FFFFFFFFFFFFFFFL / 1000000)) {
4313+
if (count < (0x7FFFFFFFFFFFFFFFL / 1000000)) {
41424314
val = (count * 1000000) / middle;
41434315
if (val < 100000) {
41444316
if (val < 100) { fmt = "%.3f"; } else
41454317
if (val < 1000) { fmt = "%.2f"; } else
4146-
{ fmt = "%.1f"; };
4318+
{ fmt = "%.1f"; };
41474319
objs[4] = Tcl_ObjPrintf(fmt, ((double)(count * 1000000)) / middle);
41484320
} else {
41494321
objs[4] = Tcl_NewWideIntObj(val);
@@ -4160,9 +4332,10 @@ Tcl_TimeRateObjCmd(
41604332
TclNewLiteralStringObj(objs[1], "\xC2\xB5s/#,"); /* mics/# */
41614333
TclNewLiteralStringObj(objs[3], "#,");
41624334
TclNewLiteralStringObj(objs[5], "#/sec");
4163-
Tcl_SetObjResult(interp, Tcl_NewListObj(6, objs));
4335+
Tcl_SetObjResult(interp, Tcl_NewListObj((!calibrate) ? 6 : 8, objarr));
41644336
}
4165-
return TCL_OK;
4337+
4338+
return result;
41664339
}
41674340

41684341
/*

0 commit comments

Comments
 (0)