Tcl Source Code

Check-in [68ebe50d7b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:fix check event source threshold (corresponds 100-ns ranges, if the wide-clicks supported); because of variable width of 1 wide-click: windows - frequency dependent, unix - nanoseconds, darwin/osx - tb.numer / tb.denom nanoseconds.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sebres-8-5-event-perf-branch
Files: files | file ages | folders
SHA1: 68ebe50d7b4b7e36fdad3933d2bc63591b442ba4
User & Date: sebres 2017-07-03 13:32:15
Context
2017-07-03
13:32
code review and small optimizations check-in: 3fc8da2b5f user: sebres tags: sebres-8-5-event-perf-branch
13:32
fix check event source threshold (corresponds 100-ns ranges, if the wide-clicks supported); because... check-in: 68ebe50d7b user: sebres tags: sebres-8-5-event-perf-branch
13:32
unix: implements wide-clicks on unix (1 wide-click == 0.001 microseconds (1 nanosecond)), so more pr... check-in: 701d66ce66 user: sebres tags: sebres-8-5-event-perf-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclNotify.c.

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
    Tcl_EventCheckProc *checkProc;
    ClientData clientData;
    struct EventSource *nextPtr;
} EventSource;

/*
 * Used for performance purposes, threshold to bypass check source (if don't wait)
 * Values under 1000 should be approximately under 1ms, e. g. 5 is ca. 0.005ms

 */
#ifndef TCL_CHECK_EVENT_SOURCE_THRESHOLD
    #define TCL_CHECK_EVENT_SOURCE_THRESHOLD 5
#endif

/*
 * The following structure keeps track of the state of the notifier on a







|
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    Tcl_EventCheckProc *checkProc;
    ClientData clientData;
    struct EventSource *nextPtr;
} EventSource;

/*
 * Used for performance purposes, threshold to bypass check source (if don't wait)
 * Value should be approximately correspond 100-ns ranges, if the wide-clicks
 * supported, it is more precise so e. g. 5 is ca. 0.5 microseconds (500-ns).
 */
#ifndef TCL_CHECK_EVENT_SOURCE_THRESHOLD
    #define TCL_CHECK_EVENT_SOURCE_THRESHOLD 5
#endif

/*
 * The following structure keeps track of the state of the notifier on a
886
887
888
889
890
891
892
893



894


































895
896
897
898
899
900
901
	    }
	    return result;
	}
    }

    return 0;
}







































/*
 *----------------------------------------------------------------------
 *
 * TclPeekEventQueued --
 *
 *	Check whether some event (except idle) available (async, queued, timer).
 *







|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
	    }
	    return result;
	}
    }

    return 0;
}

#if TCL_CHECK_EVENT_SOURCE_THRESHOLD
/*
 *----------------------------------------------------------------------
 *
 * CheckSourceThreshold --
 *
 *	Check whether we should iterate over event sources for availability.
 *
 *	This is used to avoid too unneeded overhead (too often call checkProc).
 *
 * Results:
 *	Returns 1 if threshold reached (check event sources), 0 otherwise.
 *
 *----------------------------------------------------------------------
 */

static inline int
CheckSourceThreshold(
    ThreadSpecificData *tsdPtr)
{
    /* don't need to wait/check for events too often */
#ifndef TCL_WIDE_CLICKS
    unsigned long clickdiff, clicks = TclpGetClicks();
#else
    Tcl_WideInt clickdiff, clicks;
    /* in 100-ns */
    clicks = TclpGetWideClicks() * (TclpWideClickInMicrosec() * 10);
#endif
    /* considering possible clicks-jump */
    if ( (clickdiff = (clicks - tsdPtr->lastCheckClicks)) >= 0
      && clickdiff <= TCL_CHECK_EVENT_SOURCE_THRESHOLD) {
	return 0;
    }
    tsdPtr->lastCheckClicks = clicks;
    return 1;
}
#endif

/*
 *----------------------------------------------------------------------
 *
 * TclPeekEventQueued --
 *
 *	Check whether some event (except idle) available (async, queued, timer).
 *
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948

949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

	/* once from here */
	if (!repeat) {
	    break;
	}

	if (flags & TCL_DONT_WAIT) {
    #if TCL_CHECK_EVENT_SOURCE_THRESHOLD
	    /* don't need to wait/check for events too often */
	#ifndef TCL_WIDE_CLICKS
	    unsigned long clickdiff, clicks = TclpGetClicks();
	#else
	    Tcl_WideInt clickdiff, clicks = TclpGetWideClicks();
	#endif
	    /* considering possible clicks-jump */
	    if ( (clickdiff = (clicks - tsdPtr->lastCheckClicks)) >= 0 
	      && clickdiff <= TCL_CHECK_EVENT_SOURCE_THRESHOLD) {

		return 0;
	    }
	    tsdPtr->lastCheckClicks = clicks;
    #endif
	}

	/*
	 * Check all the event sources for new events.
	 */
	for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
		sourcePtr = sourcePtr->nextPtr) {
	    if (sourcePtr->checkProc) {
		(sourcePtr->checkProc)(sourcePtr->clientData, flags);
	    }
	}
    
    } while (repeat--);

    return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * TclSetTimerEventMarker --
 *
 *	Set timer event marker to the last pending event in the queue.
 *







<

<
<
<
<
<
<
<
|
>


<

















|
<







970
971
972
973
974
975
976

977







978
979
980
981

982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999

1000
1001
1002
1003
1004
1005
1006

	/* once from here */
	if (!repeat) {
	    break;
	}

	if (flags & TCL_DONT_WAIT) {

	    /* don't need to wait/check for events too often */







    #if TCL_CHECK_EVENT_SOURCE_THRESHOLD
	    if (!CheckSourceThreshold(tsdPtr)) {
		return 0;
	    }

    #endif
	}

	/*
	 * Check all the event sources for new events.
	 */
	for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
		sourcePtr = sourcePtr->nextPtr) {
	    if (sourcePtr->checkProc) {
		(sourcePtr->checkProc)(sourcePtr->clientData, flags);
	    }
	}
    
    } while (repeat--);

    return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * TclSetTimerEventMarker --
 *
 *	Set timer event marker to the last pending event in the queue.
 *
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
	     * if setup-proc resp. check-proc will not generate new events.
	     * Force timer execution if flags specified (from checkProc).
	     */
	    tsdPtr->timerMarkerPtr = flags ? INT2PTR(-1) : INT2PTR(-2);
	};
    }
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetServiceMode --
 *
 *	This routine returns the current service mode of the notifier.
 *







|
<







1029
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039
1040
1041
1042
1043
	     * if setup-proc resp. check-proc will not generate new events.
	     * Force timer execution if flags specified (from checkProc).
	     */
	    tsdPtr->timerMarkerPtr = flags ? INT2PTR(-1) : INT2PTR(-2);
	};
    }
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetServiceMode --
 *
 *	This routine returns the current service mode of the notifier.
 *
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
int
Tcl_GetServiceMode(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    return tsdPtr->serviceMode;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetServiceMode --
 *
 *	This routine sets the current service mode of the tsdPtr->
 *







|
<







1053
1054
1055
1056
1057
1058
1059
1060

1061
1062
1063
1064
1065
1066
1067
int
Tcl_GetServiceMode(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    return tsdPtr->serviceMode;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetServiceMode --
 *
 *	This routine sets the current service mode of the tsdPtr->
 *
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
    oldMode = tsdPtr->serviceMode;
    tsdPtr->serviceMode = mode;
    if (tclStubs.tcl_ServiceModeHook) {
	tclStubs.tcl_ServiceModeHook(mode);
    }
    return oldMode;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetMaxBlockTime --
 *
 *	This function is invoked by event sources to tell the notifier how
 *	long it may block the next time it blocks. The timePtr argument gives







|
<







1085
1086
1087
1088
1089
1090
1091
1092

1093
1094
1095
1096
1097
1098
1099
    oldMode = tsdPtr->serviceMode;
    tsdPtr->serviceMode = mode;
    if (tclStubs.tcl_ServiceModeHook) {
	tclStubs.tcl_ServiceModeHook(mode);
    }
    return oldMode;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetMaxBlockTime --
 *
 *	This function is invoked by event sources to tell the notifier how
 *	long it may block the next time it blocks. The timePtr argument gives
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
     * immediately.
     */

    if (!tsdPtr->inTraversal) {
	Tcl_SetTimer(&tsdPtr->blockTime);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_DoOneEvent --
 *
 *	Process a single event of some sort. If there's no work to do, wait
 *	for an event to occur, then process it.







|
<







1129
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143
     * immediately.
     */

    if (!tsdPtr->inTraversal) {
	Tcl_SetTimer(&tsdPtr->blockTime);
    }
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_DoOneEvent --
 *
 *	Process a single event of some sort. If there's no work to do, wait
 *	for an event to occur, then process it.
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
	 * otherwise reset the block time to infinity.
	 */

	if (flags & TCL_DONT_WAIT) {

	    /* don't need to wait/check for events too often */
    #if TCL_CHECK_EVENT_SOURCE_THRESHOLD
	#ifndef TCL_WIDE_CLICKS
	    unsigned long clickdiff, clicks = TclpGetClicks();
	#else
	    Tcl_WideInt clickdiff, clicks = TclpGetWideClicks();
	#endif
	    /* considering possible clicks-jump */
	    if ( (clickdiff = (clicks - tsdPtr->lastCheckClicks)) >= 0 
	      && clickdiff <= TCL_CHECK_EVENT_SOURCE_THRESHOLD) {
		goto idleEvents;
	    }
	    tsdPtr->lastCheckClicks = clicks;
    #endif

	    tsdPtr->blockTime.sec = 0;
	    tsdPtr->blockTime.usec = 0;
	    tsdPtr->blockTimeSet = 1;
	    timePtr = &tsdPtr->blockTime;
	    goto wait; /* for notifier resp. system events */
	}








<
<
<
<
<
<
|
<


<

<







1243
1244
1245
1246
1247
1248
1249






1250

1251
1252

1253

1254
1255
1256
1257
1258
1259
1260
	 * otherwise reset the block time to infinity.
	 */

	if (flags & TCL_DONT_WAIT) {

	    /* don't need to wait/check for events too often */
    #if TCL_CHECK_EVENT_SOURCE_THRESHOLD






	    if (!CheckSourceThreshold(tsdPtr)) {

		goto idleEvents;
	    }

    #endif

	    tsdPtr->blockTime.sec = 0;
	    tsdPtr->blockTime.usec = 0;
	    tsdPtr->blockTimeSet = 1;
	    timePtr = &tsdPtr->blockTime;
	    goto wait; /* for notifier resp. system events */
	}

1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
    
    /* Reset block time earliest at the end of event cycle */
    tsdPtr->blockTimeSet = 0;

    tsdPtr->serviceMode = oldMode;
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_ServiceAll --
 *
 *	This routine checks all of the event sources, processes events that
 *	are on the Tcl event queue, and then calls the any idle handlers.







|
<







1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
    
    /* Reset block time earliest at the end of event cycle */
    tsdPtr->blockTimeSet = 0;

    tsdPtr->serviceMode = oldMode;
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_ServiceAll --
 *
 *	This routine checks all of the event sources, processes events that
 *	are on the Tcl event queue, and then calls the any idle handlers.
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
    } else {
	Tcl_SetTimer(&tsdPtr->blockTime);
    }
    tsdPtr->inTraversal = 0;
    tsdPtr->serviceMode = TCL_SERVICE_ALL;
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_ThreadAlert --
 *
 *	This function wakes up the notifier associated with the specified
 *	thread (if there is one).







|
<







1431
1432
1433
1434
1435
1436
1437
1438

1439
1440
1441
1442
1443
1444
1445
    } else {
	Tcl_SetTimer(&tsdPtr->blockTime);
    }
    tsdPtr->inTraversal = 0;
    tsdPtr->serviceMode = TCL_SERVICE_ALL;
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_ThreadAlert --
 *
 *	This function wakes up the notifier associated with the specified
 *	thread (if there is one).
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
		tclStubs.tcl_AlertNotifier(tsdPtr->clientData);
	    }
	    break;
	}
    }
    Tcl_MutexUnlock(&listLock);
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_Sleep --
 *
 *	Delay execution for the specified number of milliseconds.
 *







|
<







1472
1473
1474
1475
1476
1477
1478
1479

1480
1481
1482
1483
1484
1485
1486
		tclStubs.tcl_AlertNotifier(tsdPtr->clientData);
	    }
	    break;
	}
    }
    Tcl_MutexUnlock(&listLock);
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_Sleep --
 *
 *	Delay execution for the specified number of milliseconds.
 *