You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/03/09 01:22:16 UTC

incubator-mynewt-newt git commit: Add newt size command.

Repository: incubator-mynewt-newt
Updated Branches:
  refs/heads/rename_project_app 9468c1bc5 -> 91fac93dd


Add newt size command.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/91fac93d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/91fac93d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/91fac93d

Branch: refs/heads/rename_project_app
Commit: 91fac93ddf4fab2e8d1bdc06c1edd7e9552bf3bd
Parents: 9468c1b
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Tue Mar 8 16:21:54 2016 -0800
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 8 16:21:54 2016 -0800

----------------------------------------------------------------------
 newt/builder/cmds.go |  42 +++++-
 newt/builder/size.go | 340 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 378 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/91fac93d/newt/builder/cmds.go
----------------------------------------------------------------------
diff --git a/newt/builder/cmds.go b/newt/builder/cmds.go
index 8cbd984..1b52c41 100644
--- a/newt/builder/cmds.go
+++ b/newt/builder/cmds.go
@@ -160,12 +160,33 @@ func debugRunCmd(cmd *cobra.Command, args []string) {
 	}
 }
 
+func sizeRunCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		cli.NewtUsage(cmd, util.NewNewtError("Must specify target"))
+	}
+
+	t := target.ResolveTargetName(args[0])
+	if t == nil {
+		cli.NewtUsage(cmd, util.NewNewtError("Invalid target name"+args[0]))
+	}
+
+	b, err := NewBuilder(t)
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	err = b.Size()
+	if err != nil {
+		fmt.Println(err)
+	}
+}
+
 func AddCommands(cmd *cobra.Command) {
 	buildHelpText := ""
 	buildHelpEx := ""
 	buildCmd := &cobra.Command{
 		Use:     "build",
-		Short:   "Commands for building targets",
+		Short:   "Command for building target",
 		Long:    buildHelpText,
 		Example: buildHelpEx,
 		Run:     buildRunCmd,
@@ -177,7 +198,7 @@ func AddCommands(cmd *cobra.Command) {
 	cleanHelpEx := ""
 	cleanCmd := &cobra.Command{
 		Use:     "clean",
-		Short:   "Commands for cleaning targets",
+		Short:   "Command for cleaning target",
 		Long:    cleanHelpText,
 		Example: cleanHelpEx,
 		Run:     cleanRunCmd,
@@ -197,7 +218,7 @@ func AddCommands(cmd *cobra.Command) {
 
 	cmd.AddCommand(testCmd)
 
-	downloadHelpText := "Download project image to target for <target-name>."
+	downloadHelpText := "Download app image to target for <target-name>."
 	downloadHelpEx := "  newt download <target-name>\n"
 
 	downloadCmd := &cobra.Command{
@@ -209,7 +230,7 @@ func AddCommands(cmd *cobra.Command) {
 	}
 	cmd.AddCommand(downloadCmd)
 
-	debugHelpText := "Download project image to target for <target-name>."
+	debugHelpText := "Open debugger session for <target-name>."
 	debugHelpEx := "  newt debug <target-name>\n"
 
 	debugCmd := &cobra.Command{
@@ -220,4 +241,17 @@ func AddCommands(cmd *cobra.Command) {
 		Run:     debugRunCmd,
 	}
 	cmd.AddCommand(debugCmd)
+
+	sizeHelpText := "Calculate the size of target components specified by " +
+		"<target-name>."
+	sizeHelpEx := "  newt size <target-name>\n"
+
+	sizeCmd := &cobra.Command{
+		Use:     "size",
+		Short:   "Size of target components",
+		Long:    sizeHelpText,
+		Example: sizeHelpEx,
+		Run:     sizeRunCmd,
+	}
+	cmd.AddCommand(sizeCmd)
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/91fac93d/newt/builder/size.go
----------------------------------------------------------------------
diff --git a/newt/builder/size.go b/newt/builder/size.go
new file mode 100644
index 0000000..3579d77
--- /dev/null
+++ b/newt/builder/size.go
@@ -0,0 +1,340 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package builder
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"mynewt.apache.org/newt/newt/cli"
+	"mynewt.apache.org/newt/util"
+)
+
+/*
+ * These are different memory regions as specified in linker script.
+ */
+type MemSection struct {
+	Name   string
+	Offset uint64
+	EndOff uint64
+}
+type MemSectionArray []*MemSection
+
+func (array MemSectionArray) Len() int {
+	return len(array)
+}
+
+func (array MemSectionArray) Less(i, j int) bool {
+	return array[i].Offset < array[j].Offset
+}
+
+func (array MemSectionArray) Swap(i, j int) {
+	array[i], array[j] = array[j], array[i]
+}
+
+func MakeMemSection(name string, off uint64, size uint64) *MemSection {
+	memsection := &MemSection{
+		Name:   name,
+		Offset: off,
+		EndOff: off + size,
+	}
+	return memsection
+}
+
+func (m *MemSection) PartOf(addr uint64) bool {
+	if addr >= m.Offset && addr < m.EndOff {
+		return true
+	} else {
+		return false
+	}
+}
+
+/*
+ * We accumulate the size of libraries to elements in this.
+ */
+type PkgSize struct {
+	Name  string
+	Sizes map[string]uint32 /* Sizes indexed by mem section name */
+}
+
+type PkgSizeArray []*PkgSize
+
+func (array PkgSizeArray) Len() int {
+	return len(array)
+}
+
+func (array PkgSizeArray) Less(i, j int) bool {
+	return array[i].Name < array[j].Name
+}
+
+func (array PkgSizeArray) Swap(i, j int) {
+	array[i], array[j] = array[j], array[i]
+}
+
+func MakePkgSize(name string, memSections map[string]*MemSection) *PkgSize {
+	pkgSize := &PkgSize{
+		Name: name,
+	}
+	pkgSize.Sizes = make(map[string]uint32)
+	for secName, _ := range memSections {
+		pkgSize.Sizes[secName] = 0
+	}
+	return pkgSize
+}
+
+/*
+ * Go through GCC generated mapfile, and collect info about symbol sizes
+ */
+func ParseMapFileSizes(fileName string) (map[string]*PkgSize, map[string]*MemSection,
+	error) {
+	var state int = 0
+
+	file, err := os.Open(fileName)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	memSections := make(map[string]*MemSection)
+	pkgSizes := make(map[string]*PkgSize)
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		switch state {
+		case 0:
+			if strings.Contains(scanner.Text(), "Memory Configuration") {
+				state = 1
+			}
+		case 1:
+			if strings.Contains(scanner.Text(), "Origin") {
+				state = 2
+			}
+		case 2:
+			if strings.Contains(scanner.Text(), "*default*") {
+				state = 3
+				continue
+			}
+			array := strings.Fields(scanner.Text())
+			offset, err := strconv.ParseUint(array[1], 0, 64)
+			if err != nil {
+				return nil, nil, util.NewNewtError("Can't parse mem info")
+			}
+			size, err := strconv.ParseUint(array[2], 0, 64)
+			if err != nil {
+				return nil, nil, util.NewNewtError("Can't parse mem info")
+			}
+			memSections[array[0]] = MakeMemSection(array[0], offset,
+				size)
+		case 3:
+			if strings.Contains(scanner.Text(),
+				"Linker script and memory map") {
+				state = 4
+			}
+		case 4:
+			var addrStr string = ""
+			var sizeStr string = ""
+			var srcFile string = ""
+
+			if strings.Contains(scanner.Text(), "/DISCARD/") ||
+				strings.HasPrefix(scanner.Text(), "OUTPUT(") {
+				/*
+				 * After this there is only discarded symbols
+				 */
+				state = 5
+				continue
+			}
+
+			array := strings.Fields(scanner.Text())
+			switch len(array) {
+			case 1:
+				/*
+				 * section name on it's own, e.g.
+				 * *(.text*)
+				 *
+				 * section name + symbol name, e.g.
+				 * .text.Reset_Handler
+				 *
+				 * ignore these for now
+				 */
+				continue
+			case 2:
+				/*
+				 * Either stuff from beginning to first useful data e.g.
+				 * END GROUP
+				 *
+				 * or address of symbol + symbol name, e.g.
+				 * 0x00000000080002c8                SystemInit
+				 *
+				 * or section names with multiple input things, e.g.
+				 * *(.ARM.extab* .gnu.linkonce.armextab.*)
+				 *
+				 * or space set aside in linker script e.g.
+				 * 0x0000000020002e80      0x400
+				 * (that's the initial stack)
+				 *
+				 * ignore these for now
+				 */
+				continue
+			case 3:
+				/*
+				 * address, size, and name of file, e.g.
+				 * 0x000000000800bb04     0x1050 /Users/marko/foo/tadpole/hw//mcu/stm/stm32f3xx/bin/blinky_f3/libstm32f3xx.a(stm32f30x_syscfg.o)
+				 *
+				 * padding, or empty areas defined in linker script:
+				 * *fill*         0x000000000800cb71        0x3
+				 *
+				 * output section name, location, size, e.g.:
+				 * .bss            0x0000000020000ab0     0x23d0
+				 */
+				/*
+				 * Record addr, size and name to find library.
+				 */
+				if array[0] == "*fill*" {
+					addrStr = array[1]
+					sizeStr = array[2]
+					srcFile = array[0]
+				} else {
+					addrStr = array[0]
+					sizeStr = array[1]
+					srcFile = array[2]
+				}
+			case 4:
+				/*
+				 * section, address, size, name of file, e.g.
+				 * COMMON         0x0000000020002d28        0x8 /Users/marko/foo/tadpole/libs//os/bin/blinky_f3/libos.a(os_arch_arm.o)
+				 *
+				 * linker script symbol definitions:
+				 * 0x0000000020002e80                _ebss = .
+				 *
+				 * crud, e.g.:
+				 * 0x8 (size before relaxing)
+				 */
+				addrStr = array[1]
+				sizeStr = array[2]
+				srcFile = array[3]
+			default:
+				continue
+			}
+			addr, err := strconv.ParseUint(addrStr, 0, 64)
+			if err != nil {
+				continue
+			}
+			size, err := strconv.ParseUint(sizeStr, 0, 64)
+			if err != nil {
+				continue
+			}
+			if size == 0 {
+				continue
+			}
+			tmpStrArr := strings.Split(srcFile, "(")
+			srcLib := filepath.Base(tmpStrArr[0])
+			for name, section := range memSections {
+				if section.PartOf(addr) {
+					pkgSize := pkgSizes[srcLib]
+					if pkgSize == nil {
+						pkgSize =
+							MakePkgSize(srcLib, memSections)
+						pkgSizes[srcLib] = pkgSize
+					}
+					pkgSize.Sizes[name] += uint32(size)
+					break
+				}
+			}
+		default:
+		}
+	}
+	file.Close()
+	for name, section := range memSections {
+		cli.StatusMessage(cli.VERBOSITY_VERBOSE, "Mem %s: 0x%x-0x%x\n",
+			name, section.Offset, section.EndOff)
+	}
+
+	return pkgSizes, memSections, nil
+}
+
+/*
+ * Return a printable string containing size data for the libraries
+ */
+func PrintSizes(libs map[string]*PkgSize,
+	sectMap map[string]*MemSection) (string, error) {
+	ret := ""
+
+	/*
+	 * Order sections by offset, and display lib sizes in that order.
+	 */
+	memSections := make(MemSectionArray, len(sectMap))
+	var i int = 0
+	for _, sec := range sectMap {
+		memSections[i] = sec
+		i++
+	}
+	sort.Sort(memSections)
+
+	/*
+	 * Order libraries by name, and display them in that order.
+	 */
+	pkgSizes := make(PkgSizeArray, len(libs))
+	i = 0
+	for _, es := range libs {
+		pkgSizes[i] = es
+		i++
+	}
+	sort.Sort(pkgSizes)
+
+	for _, sec := range memSections {
+		ret += fmt.Sprintf("%7s ", sec.Name)
+	}
+	ret += "\n"
+	for _, es := range pkgSizes {
+		for i := 0; i < len(memSections); i++ {
+			ret += fmt.Sprintf("%7d ", es.Sizes[memSections[i].Name])
+		}
+		ret += fmt.Sprintf("%s\n", es.Name)
+	}
+	return ret, nil
+}
+
+func (b *Builder) Size() error {
+	if b.target.App() == nil {
+		return util.NewNewtError("app package not specified for this target")
+	}
+
+	err := b.PrepBuild()
+	if err != nil {
+		return err
+	}
+
+	mapFile := b.AppElfPath() + ".map"
+
+	pkgSizes, memSections, err := ParseMapFileSizes(mapFile)
+	if err != nil {
+		return err
+	}
+	output, err := PrintSizes(pkgSizes, memSections)
+	if err != nil {
+		return err
+	}
+	fmt.Printf("%s", output)
+	return nil
+}