Skip to content

Commit a40b2bc

Browse files
authored
Cache Parsed Enums in sotn-assets (#3124)
Adds a cache for parsed enums. Profiling showed this section was taking the majority of the runtime. The cache reduces runtime by ≈90% and enum parsing passes from 4,100 to 35 for us.
1 parent c2d677d commit a40b2bc

File tree

2 files changed

+58
-22
lines changed

2 files changed

+58
-22
lines changed

tools/sotn-assets/assets/layout/layout.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ type layouts struct {
3434
}
3535

3636
func fetchEntityIDsFromHeaderFile(overlay string) (map[int]string, error) {
37-
return sotn.FetchEnumWithMin("src/st/" + overlay, overlay, "EntityIDs", 0x100)
37+
var path = "src/st"
38+
if strings.HasPrefix(overlay, "bo") || strings.HasPrefix(overlay, "rbo") ||
39+
overlay == "mar" {
40+
path = "src/boss"
41+
}
42+
path += "/" + overlay
43+
return sotn.FetchEnumWithMin(path, overlay, "EntityIDs", 0x100)
3844
}
3945

4046
func readEntityLayoutEntry(file io.ReadSeeker, ovlName string) (layoutEntry, error) {

tools/sotn-assets/sotn/enum.go

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ import (
88
"os/exec"
99
"regexp"
1010
"strings"
11+
"sync"
1112
)
1213

1314
func removeComments(line string) string {
1415
for {
1516
start := strings.Index(line, "/*")
16-
end := strings.Index(line, "*/")
17-
if start == -1 || end == -1 || end < start {
17+
if start == -1 {
1818
break
1919
}
20-
line = line[:start] + line[end+2:]
20+
end := strings.Index(line[start+2:], "*/")
21+
if end == -1 {
22+
break
23+
}
24+
line = line[:start] + line[start+end+4:]
2125
}
2226
trailingCommentIndex := strings.Index(line, "//")
2327
if trailingCommentIndex != -1 {
@@ -38,8 +42,8 @@ func ParseCEnum(r io.Reader, name string, min int) (map[int]string, error) {
3842
nLine := 0
3943
for scanner.Scan() {
4044
nLine++
41-
line := removeComments(scanner.Text())
42-
if startRegex.MatchString(line) {
45+
line := scanner.Text()
46+
if strings.Contains(line, "enum") && startRegex.MatchString(removeComments(line)) {
4347
for scanner.Scan() {
4448
nLine++
4549
line := removeComments(scanner.Text())
@@ -81,29 +85,55 @@ func ParseCEnum(r io.Reader, name string, min int) (map[int]string, error) {
8185
return enumMap, nil
8286
}
8387

88+
// Cache keyed by: version:file:enum
89+
var enumCache = make(map[string]map[int]string)
90+
var lock = sync.RWMutex{}
91+
8492
// Read an enum from a header file after prepreprocessing
8593
func FetchEnumWithMin(srcDir, ovlName, enumName string, min int) (map[int]string, error) {
86-
header := fmt.Sprintf("%s/%s.h", srcDir, ovlName)
87-
cpp, err := exec.LookPath("cpp")
88-
cmd := exec.Command(cpp,
89-
fmt.Sprintf("-DVERSION=%s"),
90-
"-lang-c",
91-
"-Iinclude",
92-
"-Iinclude/psxsdk",
93-
"-fno-builtin",
94-
"-undef",
95-
"-P",
96-
header)
97-
o, err := cmd.Output()
94+
version := GetVersion()
95+
header := fmt.Sprintf("%s/%s.h", srcDir, ovlName)
96+
cacheKey := fmt.Sprintf("%s:%s:%s", version, header, enumName)
97+
98+
lock.RLock()
99+
parsed, ok := enumCache[cacheKey]
100+
lock.RUnlock()
101+
if ok {
102+
return parsed, nil
103+
}
104+
105+
cpp, err := exec.LookPath("cpp")
106+
if err != nil {
107+
return nil, fmt.Errorf("failed to find `cpp': %w", err)
108+
}
109+
110+
cmd := exec.Command(cpp,
111+
fmt.Sprintf("-DVERSION=%s", GetVersion()),
112+
"-lang-c",
113+
"-Iinclude",
114+
"-Iinclude/psxsdk",
115+
"-fno-builtin",
116+
"-undef",
117+
"-P",
118+
header)
119+
o, err := cmd.Output()
98120

99121
if err != nil {
100122
return nil, fmt.Errorf("failed preprocess header: %s %s: %w", cmd.Path, cmd.Args, err)
101123
}
102-
r := strings.NewReader(string(o))
103-
return ParseCEnum(r, enumName, min)
104-
}
105124

125+
r := strings.NewReader(string(o))
126+
parsed, err = ParseCEnum(r, enumName, min)
127+
128+
if err == nil {
129+
lock.Lock()
130+
enumCache[cacheKey] = parsed
131+
lock.Unlock()
132+
}
133+
134+
return parsed, err
135+
}
106136

107137
func FetchEnum(srcDir, ovlName, enumName string) (map[int]string, error) {
108-
return FetchEnumWithMin(srcDir, ovlName, enumName, 0)
138+
return FetchEnumWithMin(srcDir, ovlName, enumName, 0)
109139
}

0 commit comments

Comments
 (0)