Merge "kmem: capDL memory analyzer"
diff --git a/kmem.sh b/kmem.sh
new file mode 100755
index 0000000..c55dbdc
--- /dev/null
+++ b/kmem.sh
@@ -0,0 +1,96 @@
+#! /bin/bash
+#
+# Copyright 2022 Google LLC
+#
+# Licensed 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
+#
+# https://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.
+
+# CAmkES system image memory analyzer.
+
+# Analyze the CAmkES-generated capDL spec for memory use.
+# By default the memory foottprint of each component is displayed.
+# The -d option will give a breakdown by memory type:
+# elf .text + .data
+# bss .bss
+# ipc_buffer CAmkES per-thread ipc_buffer's
+# stack CAmkES per-thread stack
+# bootinfo Bootinfo page passed by the rooteserver
+# mmio MMIO region (backed by devivce memory)
+# copyregion VSpace region (w/o backing memory)
+#
+# Note mmio + copyregion sections do not count against memory usage as
+# they are allocated from dedicated memory that does not have physical
+# memory backing.
+#
+# TODO: account for system resources
+#
+# ROOTDIR must be set to the top of the shodan development tree
+# (as done by build/setup.sh).
+
+# Usage: kmem [-d]
+
+if [[ -z "${ROOTDIR}" ]]; then
+ echo "Source build/setup.sh first"
+ exit 1
+fi
+
+TARGET=${TARGET:-riscv32-unknown-elf}
+
+# Default is a summary of release build.
+DETAILS="0"
+BUILD="release"
+
+function parseargv {
+ local usage="Usage: kmem.sh [-h|--help] [-d|--details] [-D|--debug] [-R|--release] [-s|--summary]"
+ local args=$(getopt -o dDRs --long details,debug,release,summary,help -n kmem.sh -- "$@")
+
+ set -- $args
+
+ for i; do
+ case "$1" in
+ -d|--details)
+ DETAILS="1"
+ shift
+ ;;
+
+ -s|--summary)
+ DETAILS="0"
+ shift
+ ;;
+
+ -D|--debug)
+ BUILD="wdebug"
+ shift
+ ;;
+
+ -R|--release)
+ BUILD="release"
+ shift
+ ;;
+
+ --)
+ shift
+ break
+ ;;
+
+ -h|--help|*)
+ echo "$usage" >/dev/stderr
+ exit 1
+ ;;
+ esac
+ done
+}
+
+parseargv "$@"
+
+KATA_OUT="${ROOTDIR}/out/kata/${TARGET}/${BUILD}"
+exec awk -f "${ROOTDIR}/scripts/mem.awk" "${KATA_OUT}/system.cdl" DETAILS="${DETAILS}"
diff --git a/mem.awk b/mem.awk
new file mode 100644
index 0000000..429da6c
--- /dev/null
+++ b/mem.awk
@@ -0,0 +1,127 @@
+#
+# Copyright 2022 Google LLC
+#
+# Licensed 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
+#
+# https://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.
+
+# seL4 capDL spec memory analyzer.
+
+BEGIN {
+ in_objects = 0;
+ frame_types[1] = "elf";
+ frame_types[2] = "bss";
+ frame_types[3] = "ipc_buffer";
+ frame_types[4] = "stack";
+ frame_types[5] = "copyregion";
+ frame_types[6] = "bootinfo";
+ frame_types[7] = "mmio";
+ DETAILS = 0;
+}
+/^objects.*{/ { in_objects = 1; }
+in_objects && $3 == "frame" {
+ component = $1;
+ size = 0;
+ switch (substr($4, 2)) {
+ case /4k/: size = 4096; break;
+ case /4M/: size = 4*1024*1024; break;
+ default:
+ print "Unknown frame size", substr($4, 2);
+ break;
+ }
+
+ switch ($8) {
+ case "CDL_FrameFill_BootInfo":
+ split(component, a, "_");
+ component = a[3] "_" a[4];
+ frame_type = "bootinfo";
+ break;
+ case "CDL_FrameFill_FileData":
+ sub(".*frame_", "", component);
+ sub("_group_bin.*", "", component);
+ frame_type = "elf";
+ break;
+ default: {
+ switch (component) {
+ case /_copy_region_/:
+ sub("_copy_region.*", "", component);
+ frame_type = "copyregion";
+ break;
+ case /_frame__camkes_ipc_buffer_/:
+ sub("_frame__camkes_ipc_buffer.*", "", component);
+ frame_type = "ipc_buffer";
+ break;
+ case /^stack__camkes_stack_/:
+ sub("^stack__camkes_stack_", "", component);
+ split(component, a, "_");
+ component = a[1] "_" a[2];
+ frame_type = "stack";
+ break;
+ case /_data_[0-9]_obj/:
+ sub("_?[0-9]*_data_[0-9]_obj", "", component);
+ sub("_mmio.*", "", component);
+ frame_type = ($5 == "paddr:" ? "mmio" : "bss");
+ break;
+ default:
+ if ($5 == "paddr:") {
+ sub("_mmio.*", "", component);
+ sub("_csr_.*", "", component);
+ frame_type = "mmio";
+ } else {
+ sub(".*frame_", "", component);
+ sub("_group_bin.*", "", component);
+ frame_type = "bss";
+ }
+ break;
+ }
+ break;
+ }
+ }
+ cur_component = component;
+ if (frame_type != "copyregion" && frame_type != "mmio") {
+ # NB: copyregion's are holes in the VSpace
+ components[cur_component] += size;;
+ }
+ memory[cur_component, frame_type] += size;
+}
+in_objects && /^}/ { in_objects = 0; }
+
+END {
+ asorti(components, comps, "@ind_str_asc");
+ total = 0;
+ for (i in comps) {
+ c = comps[i];
+ ntypes = 0;
+ # per-component breakdown by frame type
+ for (j in frame_types) {
+ t = frame_types[j];
+ if (memory[c, t] != "") {
+ if (DETAILS) {
+ printf "%-36.36s %-14s %5.0f KiB\n", (ntypes > 0 ? "" : c), t, memory[c, t] / 1024.;
+ }
+ ntypes++;
+ }
+ }
+ total += components[c];
+ # per-component totals
+ if (!DETAILS) {
+ printf "%-36.36s %5.0f KiB (%s)\n", c, components[c] / 1024., components[c];
+ } else if (ntypes > 1) {
+ printf "%-36.36s %-14s %5.0f KiB (%s)\n", c, "total", components[c] / 1024., components[c];
+ }
+ }
+ # overall total
+ if (DETAILS) {
+ printf "%-36.36s %-14s %5.0f KiB (%s)\n", "Total", "", total / 1024., total;
+ } else {
+ printf "%-36.36s %5.0f KiB (%s)\n", "Total", total / 1024., total;
+ }
+}