Browse code

speed up creation of args and msg for huge cmds

Whenever a command arguments is formed by a large linked list, repeatedly
appending to arguments and displayed messages took a long time because go will
have to allocate/copy a lot of times.

This speeds up the allocation by preallocate arrays of correct size for args
and msg

Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com> (github: dqminh)

Daniel, Dao Quang Minh authored on 2014/11/12 04:37:47
Showing 1 changed files
... ...
@@ -211,6 +211,21 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
211 211
 		msg += " " + ast.Value
212 212
 	}
213 213
 
214
+	// count the number of nodes that we are going to traverse first
215
+	// so we can pre-create the argument and message array. This speeds up the
216
+	// allocation of those list a lot when they have a lot of arguments
217
+	cursor := ast
218
+	var n int
219
+	for cursor.Next != nil {
220
+		cursor = cursor.Next
221
+		n++
222
+	}
223
+	l := len(strs)
224
+	strList := make([]string, n+l)
225
+	copy(strList, strs)
226
+	msgList := make([]string, n)
227
+
228
+	var i int
214 229
 	for ast.Next != nil {
215 230
 		ast = ast.Next
216 231
 		var str string
... ...
@@ -218,16 +233,18 @@ func (b *Builder) dispatch(stepN int, ast *parser.Node) error {
218 218
 		if _, ok := replaceEnvAllowed[cmd]; ok {
219 219
 			str = b.replaceEnv(ast.Value)
220 220
 		}
221
-		strs = append(strs, str)
222
-		msg += " " + ast.Value
221
+		strList[i+l] = str
222
+		msgList[i] = ast.Value
223
+		i++
223 224
 	}
224 225
 
226
+	msg += " " + strings.Join(msgList, " ")
225 227
 	fmt.Fprintln(b.OutStream, msg)
226 228
 
227 229
 	// XXX yes, we skip any cmds that are not valid; the parser should have
228 230
 	// picked these out already.
229 231
 	if f, ok := evaluateTable[cmd]; ok {
230
-		return f(b, strs, attrs, original)
232
+		return f(b, strList, attrs, original)
231 233
 	}
232 234
 
233 235
 	fmt.Fprintf(b.ErrStream, "# Skipping unknown instruction %s\n", strings.ToUpper(cmd))