Merge "Initial version of aacdec benchmark" into main am: a76a28900a am: f697b4df6a

Original change: https://android-review.googlesource.com/c/platform/external/aac/+/3247820

Change-Id: I5e99757b6a483b6a22f42d5fa09ca0a2da8bc40f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/tests/AacDecBenchmark/AacDecBenchmark.cpp b/tests/AacDecBenchmark/AacDecBenchmark.cpp
new file mode 100644
index 0000000..6a8b421
--- /dev/null
+++ b/tests/AacDecBenchmark/AacDecBenchmark.cpp
@@ -0,0 +1,320 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * 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:
+ *
+ * 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.
+ *
+ *****************************************************************************
+ */
+
+#include <benchmark/benchmark.h>
+#include <log/log.h>
+
+#include <cstdio>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "aacdecoder_lib.h"
+
+class AACDecoder {
+   private:
+    HANDLE_AACDECODER mAACDecoder;
+    CStreamInfo* mStreamInfo;
+
+   public:
+    AACDecoder() : mAACDecoder(nullptr), mStreamInfo(nullptr) {}
+
+    bool initialize() {
+        mAACDecoder = aacDecoder_Open(TT_MP4_RAW, 1);
+        if (!mAACDecoder) {
+            ALOGE("Failed to initialize AAC decoder");
+            return false;
+        }
+
+        mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
+        if (!mStreamInfo) {
+            ALOGE("Failed to get stream info after initialization");
+            return false;
+        }
+        return true;
+    }
+
+    ~AACDecoder() {
+        if (mAACDecoder) {
+            aacDecoder_Close(mAACDecoder);
+        }
+    }
+
+    int getChannels() const { return mStreamInfo ? mStreamInfo->numChannels : 0; }
+    int getFrameSize() const { return mStreamInfo ? mStreamInfo->frameSize : 0; }
+    int getSampleRate() const { return mStreamInfo ? mStreamInfo->sampleRate : 0; }
+
+    bool decode(const std::vector<std::pair<std::vector<uint8_t>, int>>& inputBuffers) {
+        for (const auto& [buffer, flag] : inputBuffers) {
+            std::vector<INT_PCM> frameOutput;
+            if (flag == 2) {
+                if (!configureDecoder(buffer)) {
+                    return false;
+                }
+            } else {
+                if (!decodeFrame(buffer, frameOutput)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+   private:
+    bool configureDecoder(const std::vector<uint8_t>& configBuffer) {
+        UINT bytesRead = configBuffer.size();
+        UCHAR* configData = const_cast<UCHAR*>(configBuffer.data());
+        UCHAR* configArray[1] = {configData};
+
+        AAC_DECODER_ERROR err = aacDecoder_ConfigRaw(mAACDecoder, configArray, &bytesRead);
+        if (err != AAC_DEC_OK) {
+            ALOGE("Failed to configure decoder: error %d", err);
+            return false;
+        }
+        return true;
+    }
+
+    bool decodeFrame(const std::vector<uint8_t>& inputBuffer, std::vector<INT_PCM>& outputBuffer) {
+        constexpr size_t kOutputBufferSize = 10240;
+        UINT bytesRead = inputBuffer.size();
+        UINT validBytes = bytesRead;
+        UCHAR* inputPtr = const_cast<UCHAR*>(inputBuffer.data());
+        UCHAR* bufferArray[1] = {inputPtr};
+
+        AAC_DECODER_ERROR err = aacDecoder_Fill(mAACDecoder, bufferArray, &bytesRead, &validBytes);
+        if (err != AAC_DEC_OK) {
+            ALOGE("Failed to fill decoder buffer: error %d", err);
+            return false;
+        }
+
+        outputBuffer.resize(kOutputBufferSize);  // Ensure buffer is large enough
+        err = aacDecoder_DecodeFrame(mAACDecoder, outputBuffer.data(), outputBuffer.size(), 0);
+        if (err != AAC_DEC_OK) {
+            ALOGE("Failed to decode frame: error %d", err);
+            return false;
+        }
+
+        outputBuffer.resize(mStreamInfo->numChannels * mStreamInfo->frameSize);
+        return true;
+    }
+};
+
+std::vector<std::pair<std::vector<uint8_t>, int>> readInputFiles(const std::string& folderPath,
+                                                                 const std::string& bitstreamFile,
+                                                                 const std::string& infoFile) {
+    std::string fullBitstreamPath = folderPath + "/" + bitstreamFile;
+    std::string fullInfoPath = folderPath + "/" + infoFile;
+    std::vector<std::pair<std::vector<uint8_t>, int>> inputBuffers;
+
+    FILE* bitStreamFilePtr = fopen(fullBitstreamPath.c_str(), "rb");
+    if (!bitStreamFilePtr) {
+        ALOGE("Failed to open bitstream file %s", fullBitstreamPath.c_str());
+        return inputBuffers;
+    }
+
+    FILE* infoFilePtr = fopen(fullInfoPath.c_str(), "r");
+    if (!infoFilePtr) {
+        ALOGE("Failed to open info file %s", fullInfoPath.c_str());
+        return inputBuffers;
+    }
+
+    int bufferSize, flag;
+    long pts;
+
+    while (fscanf(infoFilePtr, "%d %d %ld", &bufferSize, &flag, &pts) == 3) {
+        std::vector<uint8_t> buffer(bufferSize);
+        size_t bytesRead = fread(buffer.data(), 1, bufferSize, bitStreamFilePtr);
+        if (bytesRead != bufferSize) {
+            ALOGE("Failed to read input data");
+            return std::vector<std::pair<std::vector<uint8_t>, int>>();
+        }
+        inputBuffers.emplace_back(std::move(buffer), flag);
+    }
+
+    fclose(bitStreamFilePtr);
+    fclose(infoFilePtr);
+    return inputBuffers;
+}
+
+static void BM_DecodeAAC(benchmark::State& state, const std::string& inpFolderPath,
+                         const std::string& bitstreamFile, const std::string& infoFile) {
+    auto inputBuffers = readInputFiles(inpFolderPath, bitstreamFile, infoFile);
+    if(inputBuffers.empty()) {
+        state.SkipWithError("Failed to read input data completely");
+    }
+    AACDecoder decoder;
+
+    if (!decoder.initialize()) {
+        state.SkipWithError("Unable to initialize decoder");
+    }
+
+    for (auto _ : state) {
+        if(!decoder.decode(inputBuffers)) {
+            state.SkipWithError("Unable to decode the Stream");
+        }
+    }
+
+    state.SetLabel(bitstreamFile + ", " + std::to_string(decoder.getChannels()) + ", "
+                   + std::to_string(decoder.getSampleRate()) + ", "
+                   + std::to_string(decoder.getFrameSize()));
+}
+
+// Function to register benchmarks
+void RegisterBenchmarks(const std::string& folderPath) {
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_8kHz_64kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_8kHz_64kbps_lc.bin",
+                                 "bbb_1ch_8kHz_64kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_48kHz_128kbps_lc.bin",
+                                 "bbb_1ch_48kHz_128kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_8kHz_64kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_8kHz_64kbps_lc.bin",
+                                 "bbb_2ch_8kHz_64kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_48kHz_128kbps_lc.bin",
+                                 "bbb_2ch_48kHz_128kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_8kHz_64kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_6ch_8kHz_64kbps_lc.bin",
+                                 "bbb_6ch_8kHz_64kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_lc", BM_DecodeAAC,
+                                 folderPath, "bbb_6ch_48kHz_128kbps_lc.bin",
+                                 "bbb_6ch_48kHz_128kbps_lc.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_16kHz_64kbps_he", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_16kHz_64kbps_he.bin",
+                                 "bbb_1ch_16kHz_64kbps_he.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_he", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_48kHz_128kbps_he.bin",
+                                 "bbb_1ch_48kHz_128kbps_he.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_he", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_16kHz_64kbps_he.bin",
+                                 "bbb_2ch_16kHz_64kbps_he.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_he", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_48kHz_128kbps_he.bin",
+                                 "bbb_2ch_48kHz_128kbps_he.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_hev2", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_16kHz_64kbps_hev2.bin",
+                                 "bbb_2ch_16kHz_64kbps_hev2.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_hev2", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_48kHz_128kbps_hev2.bin",
+                                 "bbb_2ch_48kHz_128kbps_hev2.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_ld", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_48kHz_128kbps_ld.bin",
+                                 "bbb_1ch_48kHz_128kbps_ld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_ld", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_48kHz_128kbps_ld.bin",
+                                 "bbb_2ch_48kHz_128kbps_ld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_ld", BM_DecodeAAC,
+                                 folderPath, "bbb_6ch_48kHz_128kbps_ld.bin",
+                                 "bbb_6ch_48kHz_128kbps_ld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_16kHz_64kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_16kHz_64kbps_eld.bin",
+                                 "bbb_1ch_16kHz_64kbps_eld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_1ch_48kHz_128kbps_eld.bin",
+                                 "bbb_1ch_48kHz_128kbps_eld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_16kHz_64kbps_eld.bin",
+                                 "bbb_2ch_16kHz_64kbps_eld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_2ch_48kHz_128kbps_eld.bin",
+                                 "bbb_2ch_48kHz_128kbps_eld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_16kHz_64kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_6ch_16kHz_64kbps_eld.bin",
+                                 "bbb_6ch_16kHz_64kbps_eld.info");
+    benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_eld", BM_DecodeAAC,
+                                 folderPath, "bbb_6ch_48kHz_128kbps_eld.bin",
+                                 "bbb_6ch_48kHz_128kbps_eld.info");
+}
+
+class CustomCsvReporter : public benchmark::BenchmarkReporter {
+   public:
+    CustomCsvReporter() : mPrintedHeader(false) {}
+    virtual bool ReportContext(const Context& context);
+    virtual void ReportRuns(const std::vector<Run>& reports);
+
+   private:
+    void PrintRunData(const Run& report);
+    bool mPrintedHeader;
+    std::vector<std::string> mHeaders = {"File",      "Channels",      "SampleRate",
+                                         "FrameSize", "real_time(ns)", "cpu_time(ns)"};
+};
+
+bool CustomCsvReporter::ReportContext(const Context& context /* __unused */) { return true; }
+
+void CustomCsvReporter::ReportRuns(const std::vector<Run>& reports) {
+    std::ostream& Out = GetOutputStream();
+
+    if (!mPrintedHeader) {
+        // print the header
+        for (auto header = mHeaders.begin(); header != mHeaders.end();) {
+            Out << *header++;
+            if (header != mHeaders.end()) Out << ",";
+        }
+        Out << "\n";
+        mPrintedHeader = true;
+    }
+
+    // print results for each run
+    for (const auto& run : reports) {
+        PrintRunData(run);
+    }
+}
+
+void CustomCsvReporter::PrintRunData(const Run& run) {
+    if (run.skipped) {
+        return;
+    }
+    std::ostream& Out = GetOutputStream();
+    Out << run.report_label << ",";
+    Out << run.GetAdjustedRealTime() << ",";
+    Out << run.GetAdjustedCPUTime() << ",";
+    Out << '\n';
+}
+
+int main(int argc, char** argv) {
+    std::unique_ptr<benchmark::BenchmarkReporter> csvReporter;
+    std::string pathArg, inpFolderPath;
+
+    for (int i = 1; i < argc; ++i) {
+        // pass --path=/path/to/resourcefolder in command line while running without atest
+        // to specify where resources are present
+        if (std::string(argv[i]).find("--path") != std::string ::npos) {
+            pathArg = argv[i];
+            auto separator = pathArg.find('=');
+            if (separator != std::string::npos) {
+                inpFolderPath = pathArg.substr(separator + 1);
+            }
+        }
+        // pass --benchmark_out=/path/to/.csv in command line to generate csv report
+        if (std::string(argv[i]).find("--benchmark_out") != std::string::npos) {
+            csvReporter.reset(new CustomCsvReporter);
+            break;
+        }
+    }
+
+    if (inpFolderPath.empty()) {
+        inpFolderPath = "/sdcard/test/AacDecBenchmark-1.0";
+    }
+    RegisterBenchmarks(inpFolderPath);
+    benchmark::Initialize(&argc, argv);
+    benchmark::RunSpecifiedBenchmarks(nullptr, csvReporter.get());
+    benchmark::Shutdown();
+    return 0;
+}
diff --git a/tests/AacDecBenchmark/Android.bp b/tests/AacDecBenchmark/Android.bp
new file mode 100644
index 0000000..58f15b2
--- /dev/null
+++ b/tests/AacDecBenchmark/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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
+//
+//      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 {
+    // See: http://go/android-license-faq
+    default_team: "trendy_team_android_media_codec_framework",
+    default_applicable_licenses: ["external_aac_license"],
+}
+
+cc_benchmark {
+    name: "AacDecBenchmark",
+    host_supported: true,
+    srcs: ["AacDecBenchmark.cpp"],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: [
+        "libFraunhoferAAC",
+        "libgoogle-benchmark",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/AacDecBenchmark/AndroidTest.xml b/tests/AacDecBenchmark/AndroidTest.xml
new file mode 100644
index 0000000..5df315d
--- /dev/null
+++ b/tests/AacDecBenchmark/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     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
+
+          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.
+-->
+<configuration description="Unit test configuration for AacDecBenchmark">
+    <option name="test-suite-tag" value="device-tests" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="AacDecBenchmark" value="/data/local/tmp/AacDecBenchmark" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="host" />
+        <option name="config-filename" value="AacDecBenchmark" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="AacDecBenchmark" />
+        <option name="version" value="1.0"/>
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+        <option name="push-all" value="true" />
+        <option name="media-folder-name" value="AacDecBenchmark-1.0" />
+        <option name="dynamic-config-module" value="AacDecBenchmark" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+        <option name="native-benchmark-device-path" value="/data/local/tmp" />
+        <option name="benchmark-module-name" value="AacDecBenchmark" />
+    </test>
+</configuration>
diff --git a/tests/AacDecBenchmark/DynamicConfig.xml b/tests/AacDecBenchmark/DynamicConfig.xml
new file mode 100644
index 0000000..48a2b94
--- /dev/null
+++ b/tests/AacDecBenchmark/DynamicConfig.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     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
+
+          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.
+-->
+
+<dynamicConfig>
+    <entry key="media_files_url">
+        <value>https://dl.google.com/android-unittest/media/external/aac/tests/AacDecBenchmark/AacDecBenchmark-1.0.zip</value>
+    </entry>
+</dynamicConfig>
diff --git a/tests/AacDecBenchmark/README.md b/tests/AacDecBenchmark/README.md
new file mode 100644
index 0000000..e60a63e
--- /dev/null
+++ b/tests/AacDecBenchmark/README.md
@@ -0,0 +1,120 @@
+# Benchmark tests
+
+This Benchmark app analyses the time taken by AAC Decoder for given set of inputs. It is used to benchmark decoder module on android devices.
+
+This page describes steps to run the AAC decoder Benchmark test.
+
+Run the following steps to build the test suite:
+```
+mmm external/aac/tests/AacDecBenchmark/
+```
+
+# Resources
+The resource folder for the tests is taken from [here](https://dl.google.com/android-unittest/media/external/aac/tests/AacDecBenchmark/AacDecBenchmark-1.0.zip)
+
+Download the AacDecBenchmark-1.0.zip folder, unzip and push it to any path on the device, Let's say the path be /sdcard/test. You can give the path wherever you chose to put the files.
+
+```
+unzip AacDecBenchmark-1.0.zip
+adb push AacDecBenchmark-1.0 /sdcard/test
+```
+
+# <a name="BenchmarkApplication"></a> Benchmark Application
+To run the test suite for measuring performance, follow the following steps:
+
+Benchmark Application can be run in two ways.
+
+## Steps to run with atest
+Note that atest command will install Benchmark application and push the required test files to the device as well.
+
+For running the benchmark test, run the following command
+```
+atest AacDecBenchmark
+```
+
+## Steps to run without atest (push binary to the device and run)
+
+To run the test suite for measuring performance of the decoder, follow the following steps:
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/benchmarktest64/
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/benchmarktest/
+
+To test 64-bit binary push binaries from benchmarktest64.
+
+```
+adb push $(OUT)/data/benchmarktest64/AacDecBenchmark/AacDecBenchmark /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from benchmarktest.
+
+```
+adb push $(OUT)/data/benchmarktest/AacDecBenchmark/AacDecBenchmark /data/local/tmp/
+```
+
+To get the resource files for the test follow instructions given in [Resources](#Resources)
+
+After running the above steps, /sdcard/test should contain AacDecBenchmark-1.0 folder and /data/local/tmp should contain benchmark binary to be executed.
+
+Run the following commands to see the benchmark results
+```
+adb shell
+cd /data/local/tmp/
+chmod a+x AacDecBenchmark
+./AacDecBenchmark
+```
+
+Run the below commands to generate a csv report and see the benchmark results
+```
+adb shell
+cd /data/local/tmp/
+chmod a+x AacDecBenchmark
+./AacDecBenchmark --benchmark_out=output.csv
+```
+
+if the folder path where the resource files are pushed is different from /sdcard/test/ , pass the actual folder path as an argument as shown below and run the following commands to see the benchmark results. Here let's say the path be /sdcard/test/AacDecBenchmark-1.0
+```
+adb shell
+cd /data/local/tmp/
+chmod a+x AacDecBenchmark
+./AacDecBenchmark --path=/sdcard/test/AacDecBenchmark-1.0
+```
+
+Run the below commands to store the benchmark results in an output.csv file which will be generated in the same path on the device.
+
+You can modify the output csv filename to any name and can be generated in any given absolute path.
+```
+adb shell
+cd /data/local/tmp/
+chmod a+x AacDecBenchmark
+./AacDecBenchmark --path=/sdcard/test/AacDecBenchmark-1.0 --benchmark_out=output.csv
+```
+
+# Analysis
+
+The benchmark results are stored in a CSV file if opted, which can be used for analysis.
+
+Note: This timestamp is in nano seconds and will change based on current system time.
+
+This csv file can be pulled from the device using "adb pull" command.
+```
+adb pull /data/local/tmp/output.csv ./output.csv
+```
+
+## CSV Columns
+
+Following columns are available in CSV.
+
+Note: All time values are in nano seconds
+
+1. **fileName**: The file being used as an input for the benchmark test.
+
+2. **Channels**: Number of channels does the input audio bitstream contain.
+
+3. **SampleRate**: SampleRate of the input audio bitstream.
+
+4. **FrameSize**: FrameSize of the input audio bitstream.
+
+5. **real_time**: Measures total elapsed time  from start to end of process, including wait times and delays.
+
+6. **cpu_time**: Measures total time spent by cpu actively executing instructions for a process.