Skip to content

Commit cb29cd1

Browse files
rscwheatman
authored andcommitted
cmd/gc: add 2-, 3-, 4-word write barrier specializations
Assignments of 2-, 3-, and 4-word values were handled by individual MOV instructions (and for scalars still are). But if there are pointers involved, those assignments now go through the write barrier routine. Before this CL, they went to writebarrierfat, which calls memmove. Memmove is too much overhead for these small amounts of data. Instead, call writebarrierfat{2,3,4}, which are specialized for the specific amount of data being copied. Today the write barrier does not care which words are pointers, so size alone is enough to distinguish the cases. If we keep these distinctions in Go 1.5 we will need to expand them for all the pointer-vs-scalar possibilities, so the current 3 functions will become 3+7+15 = 25, still not a large burden (we deleted more morestack functions than that when we dropped segmented stacks). BenchmarkBinaryTree17 3250972583 3123910344 -3.91% BenchmarkFannkuch11 3067605223 2964737839 -3.35% BenchmarkFmtFprintfEmpty 101 96.0 -4.95% BenchmarkFmtFprintfString 267 235 -11.99% BenchmarkFmtFprintfInt 261 253 -3.07% BenchmarkFmtFprintfIntInt 444 402 -9.46% BenchmarkFmtFprintfPrefixedInt 374 346 -7.49% BenchmarkFmtFprintfFloat 472 449 -4.87% BenchmarkFmtManyArgs 1537 1476 -3.97% BenchmarkGobDecode 13986528 12432985 -11.11% BenchmarkGobEncode 13120323 12537420 -4.44% BenchmarkGzip 451925758 437500578 -3.19% BenchmarkGunzip 113267612 110053644 -2.84% BenchmarkHTTPClientServer 103151 77100 -25.26% BenchmarkJSONEncode 25002733 23435278 -6.27% BenchmarkJSONDecode 94213717 8256878 -12.36% BenchmarkMandelbrot200 4804246 4713070 -1.90% BenchmarkGoParse 4646114 4379456 -5.74% BenchmarkRegexpMatchEasy0_32 163 158 -3.07% BenchmarkRegexpMatchEasy0_1K 433 391 -9.70% BenchmarkRegexpMatchEasy1_32 154 138 -10.39% BenchmarkRegexpMatchEasy1_1K 1481 1132 -23.57% BenchmarkRegexpMatchMedium_32 282 270 -4.26% BenchmarkRegexpMatchMedium_1K 92421 86149 -6.79% BenchmarkRegexpMatchHard_32 5209 4718 -9.43% BenchmarkRegexpMatchHard_1K 158141 147921 -6.46% BenchmarkRevcomp 699818791 642222464 -8.23% BenchmarkTemplate 132402383 108269713 -18.23% BenchmarkTimeParse 509 478 -6.09% BenchmarkTimeFormat 462 456 -1.30% LGTM=r R=r CC=golang-codereviews https://golang.org/cl/156200043
1 parent a0c2f1b commit cb29cd1

File tree

4 files changed

+50
-11
lines changed

4 files changed

+50
-11
lines changed

src/cmd/gc/builtin.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,12 @@ char *runtimeimport =
8484
"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
8585
"func @\"\".closechan (@\"\".hchan·1 any)\n"
8686
"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
87-
"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
8887
"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
8988
"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
89+
"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
90+
"func @\"\".writebarrierfat2 (@\"\".dst·1 *any, @\"\".src·2 any)\n"
91+
"func @\"\".writebarrierfat3 (@\"\".dst·1 *any, @\"\".src·2 any)\n"
92+
"func @\"\".writebarrierfat4 (@\"\".dst·1 *any, @\"\".src·2 any)\n"
9093
"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
9194
"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
9295
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"

src/cmd/gc/runtime.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ func writebarrierptr(dst *any, src any)
112112
func writebarrierstring(dst *any, src any)
113113
func writebarrierslice(dst *any, src any)
114114
func writebarrieriface(dst *any, src any)
115+
func writebarrierfat2(dst *any, src any)
116+
func writebarrierfat3(dst *any, src any)
117+
func writebarrierfat4(dst *any, src any)
115118
func writebarrierfat(typ *byte, dst *any, src *any)
116119

117120
func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool

src/cmd/gc/walk.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,30 +2040,42 @@ static Node*
20402040
applywritebarrier(Node *n, NodeList **init)
20412041
{
20422042
Node *l, *r;
2043+
Type *t;
20432044

20442045
if(n->left && n->right && needwritebarrier(n->left, n->right)) {
2046+
t = n->left->type;
20452047
l = nod(OADDR, n->left, N);
20462048
l->etype = 1; // addr does not escape
2047-
if(n->left->type->width == widthptr) {
2048-
n = mkcall1(writebarrierfn("writebarrierptr", n->left->type, n->right->type), T, init,
2049+
if(t->width == widthptr) {
2050+
n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
2051+
l, n->right);
2052+
} else if(t->etype == TSTRING) {
2053+
n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
2054+
l, n->right);
2055+
} else if(isslice(t)) {
2056+
n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
2057+
l, n->right);
2058+
} else if(isinter(t)) {
2059+
n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
20492060
l, n->right);
2050-
} else if(n->left->type->etype == TSTRING) {
2051-
n = mkcall1(writebarrierfn("writebarrierstring", n->left->type, n->right->type), T, init,
2061+
} else if(t->width == 2*widthptr) {
2062+
n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
20522063
l, n->right);
2053-
} else if(isslice(n->left->type)) {
2054-
n = mkcall1(writebarrierfn("writebarrierslice", n->left->type, n->right->type), T, init,
2064+
} else if(t->width == 3*widthptr) {
2065+
n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
20552066
l, n->right);
2056-
} else if(isinter(n->left->type)) {
2057-
n = mkcall1(writebarrierfn("writebarrieriface", n->left->type, n->right->type), T, init,
2067+
} else if(t->width == 4*widthptr) {
2068+
n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
20582069
l, n->right);
20592070
} else {
20602071
r = n->right;
20612072
while(r->op == OCONVNOP)
20622073
r = r->left;
20632074
r = nod(OADDR, r, N);
20642075
r->etype = 1; // addr does not escape
2065-
n = mkcall1(writebarrierfn("writebarrierfat", n->left->type, r->left->type), T, init,
2066-
typename(n->left->type), l, r);
2076+
//warnl(n->lineno, "writebarrierfat %T %N", t, r);
2077+
n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
2078+
typename(t), l, r);
20672079
}
20682080
}
20692081
return n;

src/runtime/mgc0.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
109109
dst[1] = src[1]
110110
}
111111

112+
//go:nosplit
113+
func writebarrierfat2(dst *[2]uintptr, src [2]uintptr) {
114+
dst[0] = src[0]
115+
dst[1] = src[1]
116+
}
117+
118+
//go:nosplit
119+
func writebarrierfat3(dst *[3]uintptr, src [3]uintptr) {
120+
dst[0] = src[0]
121+
dst[1] = src[1]
122+
dst[2] = src[2]
123+
}
124+
125+
//go:nosplit
126+
func writebarrierfat4(dst *[4]uintptr, src [4]uintptr) {
127+
dst[0] = src[0]
128+
dst[1] = src[1]
129+
dst[2] = src[2]
130+
dst[3] = src[3]
131+
}
132+
112133
//go:nosplit
113134
func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
114135
memmove(dst, src, typ.size)

0 commit comments

Comments
 (0)