{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/14869","repository_url":"https://api.github.com/repos/golang/go","labels_url":"https://api.github.com/repos/golang/go/issues/14869/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/14869/comments","events_url":"https://api.github.com/repos/golang/go/issues/14869/events","html_url":"https://github.com/golang/go/issues/14869","id":141968600,"number":14869,"title":"cmd/compile: SSA sometimes generates far more write barriers","user":{"login":"aclements","id":2688315,"avatar_url":"https://avatars.githubusercontent.com/u/2688315?v=3","gravatar_id":"","url":"https://api.github.com/users/aclements","html_url":"https://github.com/aclements","followers_url":"https://api.github.com/users/aclements/followers","following_url":"https://api.github.com/users/aclements/following{/other_user}","gists_url":"https://api.github.com/users/aclements/gists{/gist_id}","starred_url":"https://api.github.com/users/aclements/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aclements/subscriptions","organizations_url":"https://api.github.com/users/aclements/orgs","repos_url":"https://api.github.com/users/aclements/repos","events_url":"https://api.github.com/users/aclements/events{/privacy}","received_events_url":"https://api.github.com/users/aclements/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-03-18T20:21:28Z","updated_at":"2016-03-28T22:22:24Z","closed_at":null,"body":"I did a comparison of the write barriers produced when compiling cmd/compile with and without SSA. Sometimes it generates dramatically more write barriers than the old backend. Here are the top movers:\r\n\r\n+235 cmd/internal/obj/ppc64.buildop(SB)\r\n+72 cmd/internal/obj/mips.buildop(SB)\r\n+55 cmd/internal/obj/arm.buildop(SB)\r\n+14 cmd/compile/internal/amd64.ssaGenBlock(SB)\r\n+10 cmd/compile/internal/ssa.rewriteValuegeneric_OpStructSelect(SB)\r\n+9 cmd/compile/internal/ssa.decomposeBuiltIn(SB)\r\n+8 cmd/compile/internal/ssa.nilcheckelim(SB)\r\n+6 runtime.getitab(SB)\r\n+5 runtime.(*TypeAssertionError).Error(SB)\r\n+4 runtime.assertI2T(SB)\r\n+4 reflect.Value.MapKeys(SB)\r\n+4 fmt.(*pp).printReflectValue(SB)\r\n+4 cmd/compile/internal/ssa.(*Value).LongString(SB)\r\n+4 cmd/compile/internal/ssa.(*edgeState).setup(SB)\r\n+3 runtime.assertE2T(SB)\r\n+3 reflect.(*structType).FieldByNameFunc(SB)\r\n+3 cmd/internal/obj.Linknew(SB)\r\n+3 cmd/compile/internal/gc.typecheck1(SB)\r\n+3 cmd/compile/internal/gc.Main(SB)\r\n\r\nI looked into a few of these and it looks like the old backend is generating one call to typedmemmove in cases where SSA is generating a huge number of calls to writebarrierptr. In the smaller movers like runtime.getitab this may actually be the right thing; if there are just a few pointers, writebarrierptr is better. But 235 more write barriers is probably not the right thing.\r\n\r\nThis was generated with the following script:\r\n\r\n```\r\n#!/bin/bash\r\n\r\nawk '\r\nfunction dump() {\r\n  if (fn != \"\")\r\n    counts[fn][file] = n\r\n}\r\n/^TEXT/ { dump(); fn=$2; n=0 }\r\n/CALL runtime.writebarrierptr/ { n++ }\r\nEND {\r\n  dump();\r\n  for (fn in counts) {\r\n    printf(\"%+d %s\\n\", counts[fn][\"b\"] - counts[fn][\"a\"], fn)\r\n  }\r\n}\r\n' file=a <(go tool objdump \"$1\") file=b <(go tool objdump \"$2\") | sort -gr\r\n```\r\n\r\n/cc @khr @dr2chase "},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/202602862","html_url":"https://github.com/golang/go/issues/14869#issuecomment-202602862","issue_url":"https://api.github.com/repos/golang/go/issues/14869","id":202602862,"user":{"login":"aclements","id":2688315,"avatar_url":"https://avatars.githubusercontent.com/u/2688315?v=3","gravatar_id":"","url":"https://api.github.com/users/aclements","html_url":"https://github.com/aclements","followers_url":"https://api.github.com/users/aclements/followers","following_url":"https://api.github.com/users/aclements/following{/other_user}","gists_url":"https://api.github.com/users/aclements/gists{/gist_id}","starred_url":"https://api.github.com/users/aclements/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aclements/subscriptions","organizations_url":"https://api.github.com/users/aclements/orgs","repos_url":"https://api.github.com/users/aclements/repos","events_url":"https://api.github.com/users/aclements/events{/privacy}","received_events_url":"https://api.github.com/users/aclements/received_events","type":"User","site_admin":false},"created_at":"2016-03-28T22:22:24Z","updated_at":"2016-03-28T22:22:24Z","body":"You're right. Second column is diff in typedmemmove calls:\r\n\r\n```\r\n+235 -235 cmd/internal/obj/ppc64.buildop(SB)\r\n+72 -72 cmd/internal/obj/mips.buildop(SB)\r\n+55 -55 cmd/internal/obj/arm.buildop(SB)\r\n+14 -7 cmd/compile/internal/amd64.ssaGenBlock(SB)\r\n+10 -10 cmd/compile/internal/ssa.rewriteValuegeneric_OpStructSelect(SB)\r\n+9 +0 cmd/compile/internal/ssa.decomposeBuiltIn(SB)\r\n+8 -4 cmd/compile/internal/ssa.nilcheckelim(SB)\r\n+6 -6 runtime.getitab(SB)\r\n+5 -5 runtime.(*TypeAssertionError).Error(SB)\r\n+4 -4 runtime.assertI2T(SB)\r\n+4 -4 cmd/compile/internal/ssa.(*Value).LongString(SB)\r\n```\r\n\r\nLooks like SSA is doing much better than the old backend in general. The only weird one is decomposeBuiltIn, where SSA generating two writebarrierptrs for each mapaccess/append/mapassign line instead of one."}}