Tcl Source Code

Check-in [246fae69b1]
Login

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

Overview
Comment:increase cache size (4 now, can be configurable later), free cache in lock, more performance test-cases
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | sebres-encoding-perf-branch
Files: files | file ages | folders
SHA3-256: 246fae69b1e1211d76e6e5c725a29ae89e20653904d4503cfe6d8f2fc35f19bd
User & Date: sebres 2024-04-26 13:54:16
Context
2024-04-26
13:54
increase cache size (4 now, can be configurable later), free cache in lock, more performance test-ca... Leaf check-in: 246fae69b1 user: sebres tags: sebres-encoding-perf-branch
13:50
tests-perf/encoding.perf.tcl: added performance regression tests for encoding check-in: 4674324491 user: sebres tags: sebres-encoding-perf-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclEncoding.c.

184
185
186
187
188
189
190
191
192
193

194
195
196
197
198
199
200
201
 */

#define defaultEncoding tclIdentityEncoding
static Tcl_Encoding systemEncoding = NULL;
Tcl_Encoding tclIdentityEncoding = NULL;

/*
 * Small encoding cache (GC) hold 2 last freed encodings, to avoid too often
 * load of encodings by reuse.
 */

static Encoding *encodingCache[2] = {NULL, NULL};

/*
 * The following variable is used in the sparse matrix code for a
 * TableEncoding to represent a page in the table that has no entries.
 */

static unsigned short emptyPage[256];







|


>
|







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
 */

#define defaultEncoding tclIdentityEncoding
static Tcl_Encoding systemEncoding = NULL;
Tcl_Encoding tclIdentityEncoding = NULL;

/*
 * Small encoding cache (GC) hold N last freed encodings, to avoid too often
 * load of encodings by reuse.
 */
#define ENC_CACHE_SIZE 4
static Encoding *encodingCache[ENC_CACHE_SIZE] = {NULL, NULL, NULL, NULL};

/*
 * The following variable is used in the sparse matrix code for a
 * TableEncoding to represent a page in the table that has no entries.
 */

static unsigned short emptyPage[256];
299
300
301
302
303
304
305

306
307
308
309
310
311


312
313
314
315


316
317
318
319
320
321
322
	 * than systemEncoding got switched, retry (systemEncoding already points
	 * to other value).
	 */
    } while (1);
}

static inline

FreeEncodingCache()
{
    if (encodingCache[1]) {
	FreeEncoding(encodingCache[1], 0);
	encodingCache[1] = NULL;
    }


    if (encodingCache[0]) {
	FreeEncoding(encodingCache[0], 0);
	encodingCache[0] = NULL;
    }


}

/*
 * A Tcl_ObjType for holding a cached Tcl_Encoding in the ptrAndLongRep.ptr field
 * of the intrep. This should help the lifetime of encodings be more useful.
 * See concerns raised in [Bug 1077262].
 */







>


|
<
<
|
>
>
|
|
|
|
>
>







300
301
302
303
304
305
306
307
308
309
310


311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
	 * than systemEncoding got switched, retry (systemEncoding already points
	 * to other value).
	 */
    } while (1);
}

static inline
void
FreeEncodingCache()
{
    int i;



    Tcl_MutexLock(&encodingMutex);
    for (i = ENC_CACHE_SIZE-1; i >= 0; i--) {
	if (encodingCache[i]) {
	    FreeEncoding(encodingCache[i], 0);
	    encodingCache[i] = NULL;
	}
    }
    Tcl_MutexUnlock(&encodingMutex);
}

/*
 * A Tcl_ObjType for holding a cached Tcl_Encoding in the ptrAndLongRep.ptr field
 * of the intrep. This should help the lifetime of encodings be more useful.
 * See concerns raised in [Bug 1077262].
 */
720
721
722
723
724
725
726


727
728
729
730
731
732
733
734
735
736
737
738
739
740
741

    if (!encodingsInitialized) {
	return;
    }

    /* increase epoch to signal all encodings are obsolete */
    encodingsEpoch++;



    Tcl_MutexLock(&encodingMutex);
    encodingsInitialized = 0;
    FreeEncoding((Encoding *)systemEncoding, 0);
    systemEncoding = NULL;
    FreeEncoding((Encoding *)defaultEncoding, 0);
    defaultEncoding = NULL;
    FreeEncodingCache();

    hPtr = Tcl_FirstHashEntry(&encodingTable, &search);
    while (hPtr != NULL) {
	/*
	 * Call FreeEncoding instead of doing it directly to handle refcounts
	 * like escape encodings use. [Bug 524674] Make sure to call
	 * Tcl_FirstHashEntry repeatedly so that all encodings are eventually







>
>







<







724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739

740
741
742
743
744
745
746

    if (!encodingsInitialized) {
	return;
    }

    /* increase epoch to signal all encodings are obsolete */
    encodingsEpoch++;

    FreeEncodingCache();

    Tcl_MutexLock(&encodingMutex);
    encodingsInitialized = 0;
    FreeEncoding((Encoding *)systemEncoding, 0);
    systemEncoding = NULL;
    FreeEncoding((Encoding *)defaultEncoding, 0);
    defaultEncoding = NULL;


    hPtr = Tcl_FirstHashEntry(&encodingTable, &search);
    while (hPtr != NULL) {
	/*
	 * Call FreeEncoding instead of doing it directly to handle refcounts
	 * like escape encodings use. [Bug 524674] Make sure to call
	 * Tcl_FirstHashEntry repeatedly so that all encodings are eventually
919
920
921
922
923
924
925


926
927
928
929
930
931

932

933
934
935
936
937
938
939
	}
	/* Cache encoding which get free, thereby avoid infinite reqursion
	 * and cache within TclFinalizeEncodingSubsystem process,
	 * also consider epoch (don't store obsolete encodings in cache) */
	if ( lock == 1 && encodingsInitialized
	  && encodingPtr->epoch >= encodingsEpoch
	) {


	    /* hold 2 last freed encodings (make it reusable) */
	    Tcl_MutexLock(&encodingMutex);
	    if (encodingCache[1]) {
		FreeEncoding(encodingCache[1], 0);
	    }
	    TclpAtomicIncrFetch(&encodingPtr->refCount);

	    encodingCache[1] = encodingCache[0];

	    encodingCache[0] = encodingPtr;
	    Tcl_MutexUnlock(&encodingMutex);
	    return;
	}
	if (encodingPtr->freeProc != NULL) {
	    (*encodingPtr->freeProc)(encodingPtr->clientData);
	}







>
>
|

|
|


>
|
>







924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
	}
	/* Cache encoding which get free, thereby avoid infinite reqursion
	 * and cache within TclFinalizeEncodingSubsystem process,
	 * also consider epoch (don't store obsolete encodings in cache) */
	if ( lock == 1 && encodingsInitialized
	  && encodingPtr->epoch >= encodingsEpoch
	) {
	    int i;

	    /* hold N last freed encodings (make it reusable) */
	    Tcl_MutexLock(&encodingMutex);
	    if (encodingCache[ENC_CACHE_SIZE-1]) {
		FreeEncoding(encodingCache[ENC_CACHE_SIZE-1], 0);
	    }
	    TclpAtomicIncrFetch(&encodingPtr->refCount);
	    for (i = ENC_CACHE_SIZE-1; i > 0; i--) {
		encodingCache[i] = encodingCache[i-1];
	    }
	    encodingCache[0] = encodingPtr;
	    Tcl_MutexUnlock(&encodingMutex);
	    return;
	}
	if (encodingPtr->freeProc != NULL) {
	    (*encodingPtr->freeProc)(encodingPtr->clientData);
	}

Changes to tests-perf/encoding.perf.tcl.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42










43
44
45
46
47
48
49
50
51
52
53
54
55
56

57
58
59
60
61
62
63

namespace eval ::tclTestPerf-Enc {

namespace path {::tclTestPerf}

proc test-encoding-object {{reptime 1000}} {
  _test_run $reptime {
    # cached encoding (utf-8 must be already there):
    {encoding convertfrom utf-8 xxx}
    {encoding convertto utf-8 xxx}
    # system encoding:
    {encoding convertfrom xxx}
    {encoding convertto xxx}
    # dynamic object :
    {encoding convertfrom [string trimright "shiftjis "] xxx}
    {encoding convertto [string trimright "shiftjis "] xxx}
    # object shimmering :
    {encoding convertfrom jis0208 xxx; llength jis0208}
    {encoding convertto jis0208 xxx; llength jis0208}
  }










}

proc test-channel-encoding {{reptime 1000}} {
  _test_run $reptime {
    setup {set o [fconfigure stdout -encoding]; list}
    # dynamic object :
    {fconfigure stdout -encoding [string trimright "shiftjis "]; fconfigure stdout -encoding $o}
    # static object (shimmering) :
    {fconfigure stdout -encoding shiftjis; fconfigure stdout -encoding $o}
  }
}

proc test {{reptime 1000}} {
  test-encoding-object $reptime

  test-channel-encoding $reptime
  puts \n**OK**
}

}; # end of ::tclTestPerf-Enc

# ------------------------------------------------------------------------







|












>
>
>
>
>
>
>
>
>
>














>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

namespace eval ::tclTestPerf-Enc {

namespace path {::tclTestPerf}

proc test-encoding-object {{reptime 1000}} {
  _test_run $reptime {
    # static object and cached encoding (utf-8 must be already there):
    {encoding convertfrom utf-8 xxx}
    {encoding convertto utf-8 xxx}
    # system encoding:
    {encoding convertfrom xxx}
    {encoding convertto xxx}
    # dynamic object :
    {encoding convertfrom [string trimright "shiftjis "] xxx}
    {encoding convertto [string trimright "shiftjis "] xxx}
    # object shimmering :
    {encoding convertfrom jis0208 xxx; llength jis0208}
    {encoding convertto jis0208 xxx; llength jis0208}
  }
}
proc test-multi-encoding {{reptime 1000}} {
  _test_run $reptime {
    # dynamic object 2x convert:
    {encoding convertfrom [string trimright "jis0208 "] [encoding convertto [string trimright "shiftjis "] xxx]}
    # dynamic object 3x convert:
    {encoding convertto [string trimright "jis0212 "] [encoding convertfrom [string trimright "jis0208 "] [encoding convertto [string trimright "shiftjis "] xxx]]}
    # dynamic object 4x convert (with nested encodings load):
    {encoding convertfrom [string trimright "iso2022-kr "] [encoding convertto [string trimright "ebcdic "] [encoding convertfrom [string trimright "dingbats "] [encoding convertto [string trimright "iso2022-jp "] xxx]]]}
  }
}

proc test-channel-encoding {{reptime 1000}} {
  _test_run $reptime {
    setup {set o [fconfigure stdout -encoding]; list}
    # dynamic object :
    {fconfigure stdout -encoding [string trimright "shiftjis "]; fconfigure stdout -encoding $o}
    # static object (shimmering) :
    {fconfigure stdout -encoding shiftjis; fconfigure stdout -encoding $o}
  }
}

proc test {{reptime 1000}} {
  test-encoding-object $reptime
  test-multi-encoding $reptime
  test-channel-encoding $reptime
  puts \n**OK**
}

}; # end of ::tclTestPerf-Enc

# ------------------------------------------------------------------------