Add functions to analyse the composition of payload.
payload_composition.js defines functions that could parse the
manifest of payload and do statistical analysis based on different
metrics. Currently, there are two functions:
1. Number of blocks (in target build) that are being operated,
categorized by the installation operations.
2. Disk usage of the payload.bin, categorized by the installation
operations.
The output is currently a list of pairs: (Operation, Number), which
can be later turned into input of visualized element.
Test: Mannual Tested.
Change-Id: I07defc23f6f04616656d8c9d3a7ecd05026bbbff
diff --git a/tools/otagui/src/components/OperationDetail.vue b/tools/otagui/src/components/OperationDetail.vue
index e2626e5..4be93ac 100644
--- a/tools/otagui/src/components/OperationDetail.vue
+++ b/tools/otagui/src/components/OperationDetail.vue
@@ -1,18 +1,18 @@
<template>
{{ mapType.get(operation.type) }}
- <p v-if="operation.dataOffset !== null">
+ <p v-if="operation.hasOwnProperty('dataOffset')">
Data offset: {{ operation.dataOffset }}
</p>
- <p v-if="operation.dataLength !== null">
+ <p v-if="operation.hasOwnProperty('dataLength')">
Data length: {{ operation.dataLength }}
</p>
- <p v-if="operation.srcExtents !== null">
+ <p v-if="operation.hasOwnProperty('srcExtents')">
Source: {{ operation.srcExtents.length }} extents ({{ srcTotalBlocks }}
blocks)
<br>
{{ srcBlocks }}
</p>
- <p v-if="operation.dstExtents !== null">
+ <p v-if="operation.hasOwnProperty('dstExtents')">
Destination: {{ operation.dstExtents.length }} extents ({{ dstTotalBlocks }}
blocks)
<br>
@@ -21,6 +21,8 @@
</template>
<script>
+import { numBlocks, displayBlocks } from '../services/payload_composition.js'
+
export default {
props: {
operation: {
@@ -51,16 +53,4 @@
}
},
}
-
-function numBlocks(exts) {
- const accumulator = (total, ext) => total + ext.numBlocks
- return exts.reduce(accumulator, 0)
-}
-
-function displayBlocks(exts) {
- const accumulator = (total, ext) =>
- total + '(' + ext.startBlock + ',' + ext.numBlocks + ')'
- return exts.reduce(accumulator, '')
-}
-
</script>
\ No newline at end of file
diff --git a/tools/otagui/src/components/PartialCheckbox.vue b/tools/otagui/src/components/PartialCheckbox.vue
index 426b261..fc7694f 100644
--- a/tools/otagui/src/components/PartialCheckbox.vue
+++ b/tools/otagui/src/components/PartialCheckbox.vue
@@ -34,4 +34,15 @@
},
},
}
-</script>
\ No newline at end of file
+</script>
+
+<style scoped>
+ul > li {
+ display: inline-block;
+ list-style-type: none;
+ margin-left: 5%;
+ margin-right: 5%;
+ top: 0px;
+ height: 50px;
+}
+</style>
\ No newline at end of file
diff --git a/tools/otagui/src/components/PayloadComposition.vue b/tools/otagui/src/components/PayloadComposition.vue
new file mode 100644
index 0000000..420b96d
--- /dev/null
+++ b/tools/otagui/src/components/PayloadComposition.vue
@@ -0,0 +1,71 @@
+<template>
+ <PartialCheckbox
+ v-model="partitionInclude"
+ :labels="updatePartitions"
+ />
+ <button @click="updateChart">
+ Update the chart
+ </button>
+ <div
+ v-if="listData"
+ class="list-data"
+ >
+ <pre>
+ {{ listData }}
+ </pre>
+ </div>
+</template>
+
+<script>
+import PartialCheckbox from '@/components/PartialCheckbox.vue'
+import { operatedBlockStatistics } from '../services/payload_composition.js'
+import { EchartsData } from '../services/echarts_data.js'
+import { chromeos_update_engine as update_metadata_pb } from '../services/update_metadata_pb.js'
+
+export default {
+ components: {
+ PartialCheckbox,
+ },
+ props: {
+ manifest: {
+ type: update_metadata_pb.DeltaArchiveManifest,
+ default: () => [],
+ },
+ },
+ data() {
+ return {
+ partitionInclude: new Map(),
+ echartsData: null,
+ listData: '',
+ }
+ },
+ computed: {
+ updatePartitions() {
+ return this.manifest.partitions.map((partition) => {
+ return partition.partitionName
+ })
+ },
+ },
+ mounted() {
+ this.manifest.partitions.forEach((partition) => {
+ this.partitionInclude.set(partition.partitionName, true)
+ })
+ },
+ methods: {
+ updateChart() {
+ let partitionSelected = this.manifest.partitions.filter((partition) =>
+ this.partitionInclude.get(partition.partitionName)
+ )
+ let statisticsData = operatedBlockStatistics(partitionSelected)
+ this.echartsData = new EchartsData(statisticsData)
+ this.listData = this.echartsData.listData()
+ },
+ },
+}
+</script>
+
+<style scoped>
+.list-data {
+ text-align: center;
+}
+</style>
\ No newline at end of file
diff --git a/tools/otagui/src/components/PayloadDetail.vue b/tools/otagui/src/components/PayloadDetail.vue
index 245be24..4781190 100644
--- a/tools/otagui/src/components/PayloadDetail.vue
+++ b/tools/otagui/src/components/PayloadDetail.vue
@@ -8,6 +8,10 @@
</ul>
</div>
<div v-if="payload">
+ <h3>Payload Compositin</h3>
+ <div v-if="payload.manifest">
+ <PayloadComposition :manifest="payload.manifest" />
+ </div>
<h3>Partition List</h3>
<ul v-if="payload.manifest">
<li
@@ -38,11 +42,13 @@
<script>
import PartitionDetail from './PartitionDetail.vue'
+import PayloadComposition from './PayloadComposition.vue'
import { Payload } from '@/services/payload.js'
export default {
components: {
PartitionDetail,
+ PayloadComposition,
},
props: {
zipFile: {
diff --git a/tools/otagui/src/services/echarts_data.js b/tools/otagui/src/services/echarts_data.js
new file mode 100644
index 0000000..faddeec
--- /dev/null
+++ b/tools/otagui/src/services/echarts_data.js
@@ -0,0 +1,14 @@
+// This function will be used later for generating a pie chart through eCharts
+export class EchartsData {
+ constructor(statisticData) {
+ this.statisticData = statisticData
+ }
+
+ listData() {
+ let table = ''
+ for (let [key, value] of this.statisticData) {
+ table += key + ' : ' + value.toString() + ' Blocks' + '\n'
+ }
+ return table
+ }
+}
\ No newline at end of file
diff --git a/tools/otagui/src/services/payload_composition.js b/tools/otagui/src/services/payload_composition.js
new file mode 100644
index 0000000..b5ad85d
--- /dev/null
+++ b/tools/otagui/src/services/payload_composition.js
@@ -0,0 +1,73 @@
+import { OpType } from '@/services/payload.js'
+
+/**
+ * Return a statistics over the numbers of blocks (in destination) that are
+ * being operated by different installation operation (e.g. REPLACE, BSDIFF).
+ * Only partitions that are being passed in will be included.
+ * @param {Array<PartitionUpdate>} partitions
+ * @return {Map}
+ */
+export function operatedBlockStatistics(partitions) {
+ let operatedBlocks = new Map()
+ let opType = new OpType()
+ for (let partition of partitions) {
+ for (let operation of partition.operations) {
+ let operationType = opType.mapType.get(operation.type)
+ if (!operatedBlocks.get(operationType)) {
+ operatedBlocks.set(operationType, 0)
+ }
+ operatedBlocks.set(
+ operationType,
+ operatedBlocks.get(operationType) + numBlocks(operation.dstExtents)
+ )
+ }
+ }
+ return operatedBlocks
+}
+
+/**
+ * Return a statistics over the disk usage of payload.bin, based on the type of
+ * installation operations. Only partitions that are being passed in will be
+ * included.
+ * @param {Array<PartitionUpdate>} partitions
+ * @return {Map}
+ */
+export function operatedPayloadStatistics(partitions) {
+ let operatedBlocks = new Map()
+ let opType = new OpType()
+ for (let partition of partitions) {
+ for (let operation of partition.operations) {
+ let operationType = opType.mapType.get(operation.type)
+ if (!operatedBlocks.get(operationType)) {
+ operatedBlocks.set(operationType, 0)
+ }
+ operatedBlocks.set(
+ operationType,
+ operatedBlocks.get(operationType) + operation.dataLength
+ )
+ }
+ }
+ return operatedBlocks
+}
+
+/**
+ * Calculate the number of blocks being operated
+ * @param {Array<InstallOperations>} exts
+ * @return {number}
+ */
+export function numBlocks(exts) {
+ const accumulator = (total, ext) => total + ext.numBlocks
+ return exts.reduce(accumulator, 0)
+}
+
+/**
+ * Return a string that indicates the blocks being operated
+ * in the manner of (start_block, block_length)
+ * @param {Array<InstallOperations} exts
+ * @return {string}
+ */
+export function displayBlocks(exts) {
+ const accumulator = (total, ext) =>
+ total + '(' + ext.startBlock + ',' + ext.numBlocks + ')'
+ return exts.reduce(accumulator, '')
+}
\ No newline at end of file