aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-05-26 15:32:51 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-05-29 13:15:17 +0200
commit1f710b08fc40d6077b0065a25c5d7ab5d0750e7a (patch)
treecf6b26abe4d4724a5e07902c2ada4b846f5d2708
parent108115666bf24c0ed2844f7af9be9a672849bb9c (diff)
sys: generate arrays instead of maps
Compilation of large maps is super slow. Generate arrays instead and converet to maps at runtime. Reduces build time from ~40s to ~2s. Update #182
-rw-r--r--sys/align.go2
-rw-r--r--sys/decl.go94
-rw-r--r--sysgen/sysgen.go51
3 files changed, 108 insertions, 39 deletions
diff --git a/sys/align.go b/sys/align.go
index e1ce27d56..00d464bcb 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -32,7 +32,7 @@ func initAlign() {
}
}
- for _, s := range Structs {
+ for _, s := range keyedStructs {
rec(s)
}
}
diff --git a/sys/decl.go b/sys/decl.go
index 0956a94ee..28c18d488 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -430,7 +430,86 @@ func (t *UnionType) Align() uintptr {
return align
}
-var ctors = make(map[string][]*Call)
+var (
+ CallMap = make(map[string]*Call)
+ structs map[string]Type
+ keyedStructs map[structKey]Type
+ Resources map[string]*ResourceDesc
+ ctors = make(map[string][]*Call)
+)
+
+type structKey struct {
+ name string
+ field string
+ dir Dir
+}
+
+func getStruct(key structKey) Type {
+ if structs == nil {
+ structs = make(map[string]Type)
+ keyedStructs = make(map[structKey]Type)
+ for _, str := range structArray {
+ structs[str.Name()] = str
+ }
+ }
+ str := keyedStructs[key]
+ if str == nil {
+ proto := structs[key.name]
+ if proto == nil {
+ panic(fmt.Sprintf("missing struct prototype for %v", key.name))
+ }
+ switch typed := proto.(type) {
+ case *StructType:
+ newStr := new(StructType)
+ *newStr = *typed
+ newStr.FldName = key.field
+ newStr.ArgDir = key.dir
+ str = newStr
+ case *UnionType:
+ newStr := new(UnionType)
+ *newStr = *typed
+ newStr.FldName = key.field
+ newStr.ArgDir = key.dir
+ str = newStr
+ default:
+ panic(fmt.Sprintf("unexpected type of struct prototype for %v: %+v", key.name, proto))
+ }
+ keyedStructs[key] = str
+ }
+ return str
+}
+
+func initStructFields() {
+ missed := 0
+ for _, f := range structFields {
+ untyped := keyedStructs[f.key]
+ if untyped == nil {
+ missed++
+ continue
+ }
+ switch str := untyped.(type) {
+ case *StructType:
+ str.Fields = f.fields
+ case *UnionType:
+ str.Options = f.fields
+ default:
+ panic(fmt.Sprintf("unexpected type of struct prototype for %v: %+v", f.key.name, untyped))
+ }
+ }
+ fmt.Printf("missed %v/%v\n", missed, len(structFields))
+}
+
+func resource(name string) *ResourceDesc {
+ if Resources == nil {
+ // This is first called during init of sys package, so does not need to be thread-safe.
+ // resourceArray is in sys_GOARCH.go (generated by sysgen).
+ Resources = make(map[string]*ResourceDesc)
+ for _, res := range resourceArray {
+ Resources[res.Name] = res
+ }
+ }
+ return Resources[name]
+}
// ResourceConstructors returns a list of calls that can create a resource of the given kind.
func ResourceConstructors(name string) []*Call {
@@ -438,8 +517,9 @@ func ResourceConstructors(name string) []*Call {
}
func initResources() {
- for name, res := range Resources {
- ctors[name] = resourceCtors(res.Kind, false)
+ resource("") // init resources, if it's not done yet
+ for _, res := range resourceArray {
+ ctors[res.Name] = resourceCtors(res.Kind, false)
}
}
@@ -611,16 +691,12 @@ func ForeachType(meta *Call, f func(Type)) {
}
}
-var (
- Calls []*Call
- CallMap = make(map[string]*Call)
-)
-
func init() {
- initCalls()
initStructFields()
initResources()
initAlign()
+ keyedStructs = nil
+ structs = nil
for i, c := range Calls {
c.ID = i
diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go
index 12bcf26f7..b9212cbba 100644
--- a/sysgen/sysgen.go
+++ b/sysgen/sysgen.go
@@ -147,7 +147,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W
generateResources(desc, consts, out)
generateStructs(desc, consts, out)
- fmt.Fprintf(out, "func initCalls() {\n")
+ fmt.Fprintf(out, "var Calls = []*Call{\n")
for _, s := range desc.Syscalls {
logf(4, " generate population code for %v", s.Name)
skipCurrentSyscall = ""
@@ -160,7 +160,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W
logf(0, "unsupported syscall: %v", s.CallName)
}
}
- fmt.Fprintf(out, "func() { Calls = append(Calls, &Call{Name: \"%v\", CallName: \"%v\"", s.Name, s.CallName)
+ fmt.Fprintf(out, "&Call{Name: \"%v\", CallName: \"%v\"", s.Name, s.CallName)
if len(s.Ret) != 0 {
fmt.Fprintf(out, ", Ret: ")
generateArg("", "ret", s.Ret[0], "out", s.Ret[1:], desc, consts, true, false, out)
@@ -177,7 +177,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W
logf(0, "unsupported syscall: %v due to %v", s.Name, skipCurrentSyscall)
syscallNR = -1
}
- fmt.Fprintf(out, "}, NR: %v})}()\n", syscallNR)
+ fmt.Fprintf(out, "}, NR: %v},\n", syscallNR)
}
fmt.Fprintf(out, "}\n\n")
@@ -201,7 +201,7 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write
}
sort.Sort(resArray)
- fmt.Fprintf(out, "var Resources = map[string]*ResourceDesc{\n")
+ fmt.Fprintf(out, "var resourceArray = []*ResourceDesc{\n")
for _, res := range resArray {
underlying := ""
name := res.Name
@@ -230,7 +230,7 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write
res = desc.Resources[res.Base]
}
}
- fmt.Fprintf(out, "\"%v\": &ResourceDesc{Name: \"%v\", Type: ", name, name)
+ fmt.Fprintf(out, "&ResourceDesc{Name: \"%v\", Type: ", name)
generateArg("", "resource-type", underlying, "inout", nil, desc, consts, true, true, out)
fmt.Fprintf(out, ", Kind: []string{")
for i, k := range kind {
@@ -260,7 +260,7 @@ type structKey struct {
dir string
}
-func generateStructEntry(str Struct, key structKey, out io.Writer) {
+func generateStructEntry(str Struct, out io.Writer) {
typ := "StructType"
if str.IsUnion {
typ = "UnionType"
@@ -277,36 +277,29 @@ func generateStructEntry(str Struct, key structKey, out io.Writer) {
if str.Align != 0 {
align = fmt.Sprintf(", align: %v", str.Align)
}
- fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", FldName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n",
- key, typ, key.name, key.field, fmtDir(key.dir), false, packed, align, varlen)
+ fmt.Fprintf(out, "&%v{TypeCommon: TypeCommon{TypeName: \"%v\", IsOptional: %v} %v %v %v},\n",
+ typ, str.Name, false, packed, align, varlen)
}
func generateStructFields(str Struct, key structKey, desc *Description, consts map[string]uint64, out io.Writer) {
- typ := "StructType"
- fields := "Fields"
- if str.IsUnion {
- typ = "UnionType"
- fields = "Options"
- }
- fmt.Fprintf(out, "func() { s := Structs[\"%v\"].(*%v)\n", key, typ)
+ fmt.Fprintf(out, "{structKey{\"%v\", \"%v\", %v}, []Type{\n", key.name, key.field, fmtDir(key.dir))
for _, a := range str.Flds {
- fmt.Fprintf(out, "s.%v = append(s.%v, ", fields, fields)
generateArg(str.Name, a[0], a[1], key.dir, a[2:], desc, consts, false, true, out)
- fmt.Fprintf(out, ")\n")
+ fmt.Fprintf(out, ",\n")
}
- fmt.Fprintf(out, "}()\n")
+ fmt.Fprintf(out, "}},\n")
+
}
func generateStructs(desc *Description, consts map[string]uint64, out io.Writer) {
// Struct fields can refer to other structs. Go compiler won't like if
- // we refer to Structs map during Structs map initialization. So we do
- // it in 2 passes: on the first pass create types and assign them to
- // the map, on the second pass fill in fields.
+ // we refer to Structs during Structs initialization. So we do
+ // it in 2 passes: on the first pass create struct types without fields,
+ // on the second pass we fill in fields.
// Since structs of the same type can be fields with different names
// of multiple other structs, we have an instance of those structs
- // for each field indexed by the name of the parent struct and the
- // field name.
+ // for each field indexed by the name of the parent struct, field name and dir.
structMap := make(map[structKey]Struct)
for _, str := range desc.Structs {
@@ -322,13 +315,13 @@ func generateStructs(desc *Description, consts map[string]uint64, out io.Writer)
}
}
- fmt.Fprintf(out, "var Structs = map[string]Type{\n")
- for key, str := range structMap {
- generateStructEntry(str, key, out)
+ fmt.Fprintf(out, "var structArray = []Type{\n")
+ for _, str := range desc.Structs {
+ generateStructEntry(str, out)
}
fmt.Fprintf(out, "}\n")
- fmt.Fprintf(out, "func initStructFields() {\n")
+ fmt.Fprintf(out, "var structFields = []struct{key structKey; fields []Type}{")
for key, str := range structMap {
generateStructFields(str, key, desc, consts, out)
}
@@ -692,12 +685,12 @@ func generateArg(
if len(a) != 0 {
failf("struct '%v' has args", typ)
}
- fmt.Fprintf(out, "Structs[\"%v\"]", structKey{typ, origName, dir})
+ fmt.Fprintf(out, "getStruct(structKey{\"%v\", \"%v\", %v})", typ, origName, fmtDir(dir))
} else if _, ok := desc.Resources[typ]; ok {
if len(a) != 0 {
failf("resource '%v' has args", typ)
}
- fmt.Fprintf(out, "&ResourceType{%v, Desc: Resources[\"%v\"]}", common(), typ)
+ fmt.Fprintf(out, "&ResourceType{%v, Desc: resource(\"%v\")}", common(), typ)
return
} else {
failf("unknown arg type \"%v\" for %v", typ, name)