Skip to content

Commit 58c31f6

Browse files
author
Steve Powell
committed
Merge branch 'youngm-initial_memory'
* youngm-initial_memory: Refactor pull request 1 Support for initial memory sizes
2 parents 2cac23b + ebded49 commit 58c31f6

File tree

6 files changed

+210
-38
lines changed

6 files changed

+210
-38
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66
[Install Go][] and then `get` the memory calculator (in the Go source tree).
77

88
We run our tests with [Ginkgo/Gomega][] and manage dependencies with [Godep][].
9-
Ginkgo is one of the dependencies we manage, so get Godep before starting work.
9+
Ginkgo is one of the dependencies we manage, so get Godep before starting work:
1010

1111
```shell
1212
go get -v github.com/cloudfoundry/java-buildpack-memory-calculator
1313
cd src/github.com/cloudfoundry/java-buildpack-memory-calculator
1414

1515
go get -v github.com/tools/godep
1616
```
17+
1718
(The `-v` options on `go get` are there so you can see what packages are compiled under the covers.)
1819

1920
The (bash) script `scripts/runTests` uses (the correct version of) Ginkgo to
2021
run the tests (using the correct versions of the dependencies). `runTests`
2122
will recompile Ginkgo if necessary.
2223

23-
The parameters to runTests are passed directly to Ginkgo. For example:
24+
The parameters to `runTests` are passed directly to Ginkgo. For example:
2425

2526
```shell
2627
scripts/runTests -r=false memory
@@ -38,7 +39,7 @@ To develop against the code, you should issue:
3839
```shell
3940
godep restore
4041
```
41-
in the project directory before running tests or building from the command line.
42+
in the project directory before building or running tests directly from the command line.
4243

4344
If you wish to develop against a particular tagged *version* then, in the
4445
project directory, you need to checkout this version (using
@@ -49,6 +50,15 @@ obtained, or else it cannot be (re)set to the version this project depends on.
4950
Normally `go get -u <project>` for the dependency in error will then allow
5051
`godep restore` to complete normally.
5152

53+
### Release binaries
54+
55+
The executables are built for more than one platform, so the Go compiler must exist
56+
for the target platforms we need (currently linux and darwin). The shell script (`buildReleases`)
57+
will use the Go compiler with the `GOOS` environment variable to generate the executables.
58+
59+
This will not work if the Go installation doesn't support all these platforms, so you may have to
60+
ensure Go is installed with cross-compiler support.
61+
5262
[Install Go]: http://golang.org/doc/install
5363
[Godep]: http://github.com/tools/godep
5464
[Ginkgo/Gomega]: http://github.com/onsi/ginkgo

flags/validate_flags.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
totalFlag = "totMemory"
3232
weightsFlag = "memoryWeights"
3333
sizesFlag = "memorySizes"
34+
initialsFlag = "memoryInitials"
3435
)
3536

3637
func printHelp() {
@@ -51,10 +52,13 @@ var (
5152
memorySizes = flag.String(sizesFlag, "",
5253
"the size ranges allowed for each memory type, "+
5354
"e.g. 'heap:128m..1G,permgen:64m,stack:2m..4m,native:100m..'")
55+
memoryInitials = flag.String(initialsFlag, "",
56+
"the initial values for each memory type, "+
57+
"e.g. 'heap:128m,permgen:64m'")
5458
)
5559

5660
// Validate flags passed on command line; exit(1) if invalid; exit(2) if help printed
57-
func ValidateFlags() (memSize memory.MemSize, weights map[string]float64, sizes map[string]memory.Range) {
61+
func ValidateFlags() (memSize memory.MemSize, weights map[string]float64, sizes map[string]memory.Range, initials map[string]float64) {
5862

5963
flag.Parse() // exit on error
6064

@@ -67,8 +71,9 @@ func ValidateFlags() (memSize memory.MemSize, weights map[string]float64, sizes
6771
memSize = validateTotMemory(*totMemory)
6872
weights = validateWeights(*memoryWeights)
6973
sizes = validateSizes(*memorySizes)
74+
initials = validateInitials(*memoryInitials)
7075

71-
return memSize, weights, sizes
76+
return memSize, weights, sizes, initials
7277
}
7378

7479
func validateTotMemory(mem string) memory.MemSize {
@@ -140,6 +145,39 @@ func validateSizes(sizes string) map[string]memory.Range {
140145
return rs
141146
}
142147

148+
func validateInitials(initials string) map[string]float64 {
149+
is := map[string]float64{}
150+
151+
if initials == "" {
152+
return is
153+
}
154+
155+
initialClauses := strings.Split(initials, ",")
156+
for _, clause := range initialClauses {
157+
if parts := strings.Split(clause, ":"); len(parts) == 2 {
158+
if !strings.HasSuffix(parts[1], "%") {
159+
fmt.Fprintf(os.Stderr, "Bad initial value in -%s flag; clause '%s' : value must be a percentage (e.g. 10%%)", initialsFlag, clause)
160+
os.Exit(1)
161+
}
162+
if floatVal, err := strconv.ParseFloat(strings.Replace(parts[1], "%", "", 1), 32); err != nil {
163+
fmt.Fprintf(os.Stderr, "Bad initial value in -%s flag; clause '%s' : %s", initialsFlag, clause, err)
164+
os.Exit(1)
165+
} else if floatVal < 0.0 || floatVal > 100.0 {
166+
fmt.Fprintf(os.Stderr, "Initial value must be zero or more but no more than 100%% in -%s flag; clause '%s'", initialsFlag, clause)
167+
os.Exit(1)
168+
} else {
169+
//Convert value to valid scale factor
170+
is[parts[0]] = floatVal * .01
171+
}
172+
} else {
173+
fmt.Fprintf(os.Stderr, "Bad clause '%s' in -%s flag", clause, initialsFlag)
174+
os.Exit(1)
175+
}
176+
}
177+
178+
return is
179+
}
180+
143181
func noArgs(args []string) bool {
144182
return len(args) == 0
145183
}

integration/main_test.go

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,67 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
8888
Ω(string(se)).Should(ContainSubstring("Total memory (-totMemory flag) is less than 1K"), "stderr incorrect for "+badFlags[0])
8989
})
9090

91+
It("executes with error when initial is not a percentage", func() {
92+
badFlags :=
93+
[]string{
94+
"-totMemory=2G",
95+
"-memoryWeights=heap:5,stack:1,permgen:3,native:1",
96+
"-memorySizes=stack:2m..,heap:30m..400m,permgen:10m..12m",
97+
"-memoryInitials=heap:50",
98+
}
99+
so, se, err := runOutAndErr(badFlags...)
100+
Ω(err).Should(HaveOccurred(), badFlags[0])
101+
102+
Ω(string(so)).Should(BeEmpty(), "stdout not empty for "+badFlags[0])
103+
Ω(string(se)).Should(ContainSubstring("Bad initial value in -memoryInitials flag; clause 'heap:50' : value must be a percentage (e.g. 10%)"), "stderr incorrect for "+badFlags[0])
104+
})
105+
106+
It("executes with error when initial too big", func() {
107+
badFlags :=
108+
[]string{
109+
"-totMemory=2G",
110+
"-memoryWeights=heap:5,stack:1,permgen:3,native:1",
111+
"-memorySizes=stack:2m..,heap:30m..400m,permgen:10m..12m",
112+
"-memoryInitials=heap:101%",
113+
}
114+
so, se, err := runOutAndErr(badFlags...)
115+
Ω(err).Should(HaveOccurred(), badFlags[0])
116+
117+
Ω(string(so)).Should(BeEmpty(), "stdout not empty for "+badFlags[0])
118+
Ω(string(se)).Should(ContainSubstring("Initial value must be zero or more but no more than 100% in -memoryInitials flag; clause 'heap:101%'"), "stderr incorrect for "+badFlags[0])
119+
})
120+
121+
It("executes with error when initial is negative", func() {
122+
badFlags :=
123+
[]string{
124+
"-totMemory=2G",
125+
"-memoryWeights=heap:5,stack:1,permgen:3,native:1",
126+
"-memorySizes=stack:2m..,heap:30m..400m,permgen:10m..12m",
127+
"-memoryInitials=heap:-1%",
128+
}
129+
so, se, err := runOutAndErr(badFlags...)
130+
Ω(err).Should(HaveOccurred(), badFlags[0])
131+
132+
Ω(string(so)).Should(BeEmpty(), "stdout not empty for "+badFlags[0])
133+
Ω(string(se)).Should(ContainSubstring("Initial value must be zero or more but no more than 100% in -memoryInitials flag; clause 'heap:-1%'"), "stderr incorrect for "+badFlags[0])
134+
})
135+
91136
Context("with valid parameters", func() {
92137
var (
93-
totMemFlag, weightsFlag, sizesFlag string
94-
sOut, sErr []byte
95-
cmdErr error
138+
totMemFlag, weightsFlag, sizesFlag, initialsFlag string
139+
sOut, sErr []byte
140+
cmdErr error
96141
)
97142

98143
BeforeEach(func() {
99144
totMemFlag = "-totMemory=4g"
100145
weightsFlag = "-memoryWeights=heap:5,stack:1,permgen:3,native:1"
101146
sizesFlag = "-memorySizes=stack:1m"
147+
initialsFlag = "-memoryInitials=heap:50%,permgen:50%"
102148
})
103149

104150
JustBeforeEach(func() {
105-
goodFlags := []string{totMemFlag, weightsFlag, sizesFlag}
151+
goodFlags := []string{totMemFlag, weightsFlag, sizesFlag, initialsFlag}
106152
sOut, sErr, cmdErr = runOutAndErr(goodFlags...)
107153
})
108154

@@ -111,6 +157,7 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
111157
totMemFlag = "-totMemory=4g"
112158
weightsFlag = ""
113159
sizesFlag = ""
160+
initialsFlag = ""
114161
})
115162

116163
It("succeeds", func() {
@@ -120,6 +167,22 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
120167
})
121168
})
122169

170+
Context("using no memoryInitials parameter", func() {
171+
BeforeEach(func() {
172+
initialsFlag = ""
173+
})
174+
175+
It("succeeds", func() {
176+
Ω(cmdErr).ShouldNot(HaveOccurred(), "exit status")
177+
Ω(string(sErr)).Should(Equal(""), "stderr")
178+
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
179+
"-Xmx2G",
180+
"-Xss1M",
181+
"-XX:MaxPermSize=1258291K",
182+
), "stdout")
183+
})
184+
})
185+
123186
Context("using permgen", func() {
124187
BeforeEach(func() {
125188
totMemFlag = "-totMemory=4g"
@@ -131,10 +194,10 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
131194
Ω(string(sErr)).Should(Equal(""), "stderr")
132195
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
133196
"-Xmx2G",
134-
"-Xms2G",
197+
"-Xms1G",
135198
"-Xss1M",
136199
"-XX:MaxPermSize=1258291K",
137-
"-XX:PermSize=1258291K",
200+
"-XX:PermSize=629145K",
138201
), "stdout")
139202
})
140203
})
@@ -143,17 +206,18 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
143206
BeforeEach(func() {
144207
totMemFlag = "-totMemory=4g"
145208
weightsFlag = "-memoryWeights=heap:5,stack:1,metaspace:3,native:1"
209+
initialsFlag = "-memoryInitials=heap:50%,metaspace:50%"
146210
})
147211

148212
It("succeeds", func() {
149213
Ω(cmdErr).ShouldNot(HaveOccurred(), "exit status")
150214
Ω(string(sErr)).Should(Equal(""), "stderr")
151215
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
152216
"-Xmx2G",
153-
"-Xms2G",
217+
"-Xms1G",
154218
"-Xss1M",
155219
"-XX:MaxMetaspaceSize=1258291K",
156-
"-XX:MetaspaceSize=1258291K",
220+
"-XX:MetaspaceSize=629145K",
157221
), "stdout")
158222
})
159223
})
@@ -184,10 +248,10 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
184248
Ω(string(sErr)).Should(Equal("There is more than 3 times more spare native memory than the default so configured Java memory may be too small or available memory may be too large\n"), "stderr")
185249
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
186250
"-Xmx800M",
187-
"-Xms800M",
251+
"-Xms400M",
188252
"-Xss3120K",
189253
"-XX:MaxPermSize=800M",
190-
"-XX:PermSize=800M",
254+
"-XX:PermSize=400M",
191255
), "stdout")
192256
})
193257
})
@@ -201,7 +265,7 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
201265

202266
It("issues a warning", func() {
203267
Ω(cmdErr).ShouldNot(HaveOccurred(), "exit status")
204-
Ω(string(sErr)).Should(Equal("The allocated Java memory sizes total 2469478K which is less than 0.8 of the available memory, so configured Java memory sizes may be too small or available memory may be too large\n"), "stderr")
268+
Ω(string(sErr)).Should(ContainSubstring("The allocated Java memory sizes total 2469478K which is less than 0.8 of the available memory, so configured Java memory sizes may be too small or available memory may be too large\n"), "stderr")
205269
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
206270
"-XX:MaxPermSize=1M",
207271
"-XX:PermSize=1M",
@@ -224,9 +288,9 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
224288
Ω(string(sErr)).Should(Equal("The specified value 2049M for memory type heap is close to the computed value 2G. Consider taking the default.\n"), "stderr")
225289
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
226290
"-XX:MaxPermSize=1257676K",
227-
"-XX:PermSize=1257676K",
291+
"-XX:PermSize=628838K",
228292
"-Xmx2049M",
229-
"-Xms2049M",
293+
"-Xms1049088K",
230294
"-Xss1023K",
231295
), "stdout")
232296
})
@@ -245,9 +309,25 @@ var _ = Describe("java-buildpack-memory-calculator executable", func() {
245309
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
246310
"-Xss984K",
247311
"-XX:MaxPermSize=1339M",
248-
"-XX:PermSize=1339M",
312+
"-XX:PermSize=685568K",
249313
"-Xmx2016548K",
250-
"-Xms2016548K",
314+
"-Xms1008274K",
315+
), "stdout")
316+
})
317+
})
318+
Context("when the specified initial memory is less than static minimum", func() {
319+
BeforeEach(func() {
320+
initialsFlag = "-memoryInitials=heap:0%"
321+
})
322+
323+
It("issues a warning", func() {
324+
Ω(cmdErr).ShouldNot(HaveOccurred(), "exit status")
325+
Ω(string(sErr)).Should(Equal("The configured initial memory size 0 for heap is less than the minimum 2M. Setting initial value to 2M.\n"), "stderr")
326+
Ω(strings.Split(string(sOut), " ")).Should(ConsistOf(
327+
"-Xss1M",
328+
"-XX:MaxPermSize=1258291K",
329+
"-Xmx2G",
330+
"-Xms2M",
251331
), "stdout")
252332
})
253333
})

main.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ const (
3333
func main() {
3434

3535
// validateFlags() will exit on error
36-
memSize, weights, sizes := flags.ValidateFlags()
37-
38-
switchFuns := switches.AllJreSwitchFuns
36+
memSize, weights, sizes, initials := flags.ValidateFlags()
3937

4038
allocator, err := memory.NewAllocator(sizes, weights)
4139
if err != nil {
@@ -47,11 +45,15 @@ func main() {
4745
fmt.Fprintf(os.Stderr, "Cannot balance memory: %s", err)
4846
os.Exit(1)
4947
}
48+
49+
allocator.GenerateInitialAllocations(initials)
50+
51+
allocatorSwitches := allocator.Switches(switches.AllocatorJreSwitchFuns)
52+
5053
if warnings := allocator.GetWarnings(); len(warnings) != 0 {
5154
fmt.Fprintln(os.Stderr, strings.Join(warnings, "\n"))
5255
}
5356

54-
switches := allocator.Switches(switchFuns)
55-
fmt.Fprint(os.Stdout, strings.Join(switches, " "))
57+
fmt.Fprint(os.Stdout, strings.Join(allocatorSwitches, " "))
5658

5759
}

0 commit comments

Comments
 (0)