diff options
author | Dan Willemsen <dwillemsen@google.com> | 2018-05-10 20:48:01 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-05-10 20:48:01 +0000 |
commit | 68d1cc59e9bb80a393952d55ab164d40c4956f38 (patch) | |
tree | 22a8ba6062c52d6b23ea57bd20adcbf253528347 /tests | |
parent | 8fb4b9ace1cefc3f414fd5c93550e232546e64f9 (diff) | |
parent | 3efdaf66081af11c9175052508163391677ab43a (diff) | |
download | extras-68d1cc59e9bb80a393952d55ab164d40c4956f38.tar.gz |
Merge "Remove sdcard_perf_test"
Diffstat (limited to 'tests')
-rw-r--r-- | tests/sdcard/Android.mk | 37 | ||||
-rw-r--r-- | tests/sdcard/README | 63 | ||||
-rwxr-xr-x | tests/sdcard/plot_sdcard.py | 334 | ||||
-rwxr-xr-x | tests/sdcard/profile_sdcard.sh | 64 | ||||
-rw-r--r-- | tests/sdcard/sdcard_perf_test.cpp | 737 | ||||
-rw-r--r-- | tests/sdcard/stopwatch.cpp | 236 | ||||
-rw-r--r-- | tests/sdcard/stopwatch.h | 156 | ||||
-rw-r--r-- | tests/sdcard/sysutil.cpp | 604 | ||||
-rw-r--r-- | tests/sdcard/sysutil.h | 146 | ||||
-rw-r--r-- | tests/sdcard/testcase.cpp | 232 | ||||
-rw-r--r-- | tests/sdcard/testcase.h | 169 |
11 files changed, 0 insertions, 2778 deletions
diff --git a/tests/sdcard/Android.mk b/tests/sdcard/Android.mk deleted file mode 100644 index d1e06f25..00000000 --- a/tests/sdcard/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2009 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. -# -# Build control file for Bionic's test programs -# define the BIONIC_TESTS environment variable to build the test programs -# - -ifdef SDCARD_TESTS - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES = \ - stopwatch.cpp \ - sysutil.cpp \ - sdcard_perf_test.cpp \ - testcase.cpp - -LOCAL_MODULE := sdcard_perf_test -LOCAL_MODULE_TAGS := eng tests -LOCAL_SHARED_LIBRARIES := libutils libhardware_legacy - -include $(BUILD_EXECUTABLE) - -endif # SDCARD_TESTS diff --git a/tests/sdcard/README b/tests/sdcard/README deleted file mode 100644 index 210bb43f..00000000 --- a/tests/sdcard/README +++ /dev/null @@ -1,63 +0,0 @@ -This directory contains tools to profile the sdcard performance. - -There are 2 parts to the tool: -* A binary that runs on the device, exercises the sdcard and send - measurment data back to the host (sdcard_perf_test). -* A host python script to plot the data. - -Additionally, there is script 'profile_sdcard.sh' that allows you -to check how the sdcard scale with the number of processes. - -INSTALLATION -============ -Build, install and mount debugfs. In this directory with a properly -configured enviroment: - - mm SDCARD_TESTS=1 - adb remount - adb push $ANDROID_PRODUCT_OUT/system/bin/sdcard_perf_test /system/bin/sdcard_perf_test - adb shell mount -t debugfs none /sys/kernel/debug - -If you want to graph the results you need gnuplot and numpy: - - sudo apt-get install gnuplot python-numpy python-numeric - -You need Gnuplot.py version 1.8 (not the one coming with ubuntu). -Download it from the Gnuplot.py web site. Extract to a temp -directory, chdir and run: - - sudo python setup.py install - - -INVOCATION -========== - -Run a simple test: - - adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 - -This test will write 1000kbyte (1M) files using writes of 100kbytes (so 10 writes per file) using -only 1 process for 100 times (100 files will be written on the sdcard). -The test will not call sync to flush the writes. -At the end of the test, some stats for the 'open' and 'write' system calls are written. - -If you want to plot the data, you need to use the --dump option and provide a file: - - adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump >/tmp/data.txt - -PLOTTING -======== - -To plot the result using the iter number of the x axis: - - plot_sdcard.py -i /tmp/data.txt - -To plot the result using time for the x axis: - - plot_sdcard.py -t /tmp/data.txt - -To plot the result from the profiler: - - profile_sdcard.sh - plot_sdcard.py -p - diff --git a/tests/sdcard/plot_sdcard.py b/tests/sdcard/plot_sdcard.py deleted file mode 100755 index 0959465c..00000000 --- a/tests/sdcard/plot_sdcard.py +++ /dev/null @@ -1,334 +0,0 @@ -#!/usr/bin/python2.5 -# -# Copyright 2009, 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. - - -"""plot_sdcard: A module to plot the results of an sdcard perf test. - -Requires Gnuplot python v 1.8 - -Typical usage: - -t x axis is time - -i x axis is iteration - -p profile data generated by profile_sdcard.sh - -./plot_sdcard.py -t /tmp/data.txt -./plot_sdcard.py -i /tmp/data.txt -./plot_sdcard.py -p - -python interpreter ->>> import plot_sdcard as p ->>> (metadata, data) = p.Parse('/tmp/data.txt') ->>> p.PlotIterations(metadata, data) ->>> p.PlotTimes(metadata, data) - -""" - -import getopt -from itertools import izip -import re -import sys -import Gnuplot -import numpy - - -class DataSet(object): - """Dataset holds the summary and data (time,value pairs).""" - - def __init__(self, line): - res = re.search(('# StopWatch ([\w]+) total/cumulative ' - 'duration ([0-9.]+). Samples: ([0-9]+)'), line) - self.time = [] - self.data = [] - self.name = res.group(1) - self.duration = float(res.group(2)) - self.iteration = int(res.group(3)) - self.summary = re.match('([a-z_]+)_total', self.name) - - def __repr__(self): - return str(zip(self.time, self.data)) - - def Add(self, time, value): - self.time.append(time) - self.data.append(value) - - def RescaleTo(self, length): - factor = len(self.data) / length - - if factor > 1: - new_time = [] - new_data = [] - accum = 0.0 - idx = 1 - for t, d in izip(self.time, self.data): - accum += d - if idx % factor == 0: - new_time.append(t) - new_data.append(accum / factor) - accum = 0 - idx += 1 - self.time = new_time - self.data = new_data - - -class Metadata(object): - def __init__(self): - self.kernel = '' - self.command_line = '' - self.sched = '' - self.name = '' - self.fadvise = '' - self.iterations = 0 - self.duration = 0.0 - self.complete = False - - def Parse(self, line): - if line.startswith('# Kernel:'): - self.kernel = re.search('Linux version ([0-9.]+-[^ ]+)', line).group(1) - elif line.startswith('# Command:'): - self.command_line = re.search('# Command: [/\w_]+ (.*)', line).group(1) - self.command_line = self.command_line.replace(' --', '-') - self.command_line = self.command_line.replace(' -d', '') - self.command_line = self.command_line.replace('--test=', '') - elif line.startswith('# Iterations'): - self.iterations = int(re.search('# Iterations: ([0-9]+)', line).group(1)) - elif line.startswith('# Fadvise'): - self.fadvise = re.search('# Fadvise: ([\w]+)', line).group(1) - elif line.startswith('# Sched'): - self.sched = re.search('# Sched features: ([\w]+)', line).group(1) - self.complete = True - - def AsTitle(self): - return '%s-duration:%f\\n-%s\\n%s' % ( - self.kernel, self.duration, self.command_line, self.sched) - - def UpdateWith(self, dataset): - self.duration = max(self.duration, dataset.duration) - self.name = dataset.name - - -def Parse(filename): - """Parse a file with the collected data. - - The data must be in 2 rows (x,y). - - Args: - filename: Full path to the file. - """ - - f = open(filename, 'r') - - metadata = Metadata() - data = [] # array of dataset - dataset = None - - for num, line in enumerate(f): - try: - line = line.strip() - if not line: continue - - if not metadata.complete: - metadata.Parse(line) - continue - - if re.match('[a-z_]', line): - continue - - if line.startswith('# StopWatch'): # Start of a new dataset - if dataset: - if dataset.summary: - metadata.UpdateWith(dataset) - else: - data.append(dataset) - - dataset = DataSet(line) - continue - - if line.startswith('#'): - continue - - # must be data at this stage - try: - (time, value) = line.split(None, 1) - except ValueError: - print 'skipping line %d: %s' % (num, line) - continue - - if dataset and not dataset.summary: - dataset.Add(float(time), float(value)) - - except Exception: - print 'Error parsing line %d' % num, sys.exc_info()[0] - raise - data.append(dataset) - if not metadata.complete: - print """Error missing metadata. Did you mount debugfs? - [adb shell mount -t debugfs none /sys/kernel/debug]""" - sys.exit(1) - return (metadata, data) - - -def PlotIterations(metadata, data): - """Plot the duration of the ops against iteration. - - If you are plotting data with widely different runtimes you probably want to - use PlotTimes instead. - - For instance when readers and writers are in the same mix, the - readers will go thru 100 iterations much faster than the - writers. The load test tries to be smart about that but the final - iterations of the writers will likely be done w/o any influence from - the readers. - - Args: - metadata: For the graph's title. - data: pair of to be plotted. - """ - - gp = Gnuplot.Gnuplot(persist=1) - gp('set data style lines') - gp.clear() - gp.xlabel('iterations') - gp.ylabel('duration in second') - gp.title(metadata.AsTitle()) - styles = {} - line_style = 1 - - for dataset in data: - dataset.RescaleTo(metadata.iterations) - x = numpy.arange(len(dataset.data), dtype='int_') - if not dataset.name in styles: - styles[dataset.name] = line_style - line_style += 1 - d = Gnuplot.Data(x, dataset.data, - title=dataset.name, - with_='lines ls %d' % styles[dataset.name]) - else: # no need to repeat a title that exists already. - d = Gnuplot.Data(x, dataset.data, - with_='lines ls %d' % styles[dataset.name]) - - gp.replot(d) - gp.hardcopy('/tmp/%s-%s-%f.png' % - (metadata.name, metadata.kernel, metadata.duration), - terminal='png') - - -def PlotTimes(metadata, data): - """Plot the duration of the ops against time elapsed. - - Args: - metadata: For the graph's title. - data: pair of to be plotted. - """ - - gp = Gnuplot.Gnuplot(persist=1) - gp('set data style impulses') - gp('set xtics 1') - gp.clear() - gp.xlabel('seconds') - gp.ylabel('duration in second') - gp.title(metadata.AsTitle()) - styles = {} - line_style = 1 - - for dataset in data: - x = numpy.array(dataset.time, dtype='float_') - if not dataset.name in styles: - styles[dataset.name] = line_style - line_style += 1 - d = Gnuplot.Data(x, dataset.data, - title=dataset.name, - with_='impulses ls %d' % styles[dataset.name]) - else: # no need to repeat a title that exists already. - d = Gnuplot.Data(x, dataset.data, - with_='impulses ls %d' % styles[dataset.name]) - - gp.replot(d) - gp.hardcopy('/tmp/%s-%s-%f.png' % - (metadata.name, metadata.kernel, metadata.duration), - terminal='png') - - -def PlotProfile(): - """Plot the time of a run against the number of processes.""" - (metadata, data) = Parse('/tmp/sdcard-scalability.txt') - gp = Gnuplot.Gnuplot(persist=1) - gp('set data style impulses') - gp('set xtics 1') - gp('set pointsize 2') - gp.clear() - gp.xlabel('writer process') - gp.ylabel('duration in second') - gp.title(metadata.AsTitle()) - - dataset = data[0] - x = numpy.array(dataset.time, dtype='int_') - d = Gnuplot.Data(x, dataset.data, - title=dataset.name, - with_='linespoints') - gp.replot(d) - gp.hardcopy('/tmp/%s-%s-%f.png' % - (metadata.name, metadata.kernel, metadata.duration), - terminal='png') - - -def Usage(): - """Print this module's usage.""" - print """ - To plot the result using the iter number of the x axis: - - plot_sdcard.py -i /tmp/data.txt - - To plot the result using time for the x axis: - - plot_sdcard.py -t /tmp/data.txt - - To plot the result from the profiler: - - profile_sdcard.sh - plot_sdcard.py -p - - """ - sys.exit(2) - - -def main(argv): - try: - (optlist, args) = getopt.getopt(argv[1:], - 'itp', ['iteration', 'time', 'profile']) - except getopt.GetoptError, err: - print str(err) - Usage() - - for flag, val in optlist: - if flag in ('-i', '--iteration'): - (metadata, data) = Parse(args[0]) - PlotIterations(metadata, data) - sys.exit(0) - elif flag in ('-t', '--time'): - (metadata, data) = Parse(args[0]) - PlotTimes(metadata, data) - sys.exit(0) - elif flag in ('-p', '--profile'): - PlotProfile() - sys.exit(0) - Usage() - - -if __name__ == '__main__': - if Gnuplot.__version__ != "1.8": - print "Gnuplot should be 1.8. See REAME file" - sys.exit(2) - main(sys.argv) diff --git a/tests/sdcard/profile_sdcard.sh b/tests/sdcard/profile_sdcard.sh deleted file mode 100755 index 4629c910..00000000 --- a/tests/sdcard/profile_sdcard.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# Copyright 2009, 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. - -# Run a bunch of test on the sdcard to establish a performance profile. - -print_kernel() { - adb shell cat /proc/version -} -print_sched_features() { - adb shell cat /sys/kernel/debug/sched_features -} - -# Use dd to get the raw speed of the card -block_level() { - true -} - -# Time to run a test vs number of processes -scalability() { - local file="/tmp/sdcard-scalability.txt" - rm -f ${file} - echo "# Scalability tests" | tee -a ${file} - echo "# Kernel: $(print_kernel)" | tee -a ${file} - echo "# Sched features: $(print_sched_features)" | tee -a ${file} - echo "# StopWatch scalability total/cumulative duration 0.0 Samples: 1" | tee -a ${file} - echo "# Process Time" | tee -a ${file} - for p in $(seq 1 8); do - adb shell sdcard_perf_test --test=write --procnb=${p} --size=1000 --chunk-size=100 --iterations=50 >/tmp/tmp-sdcard.txt - local t=$(grep 'write_total' /tmp/tmp-sdcard.txt | tail -n 1 | cut -f 6 -d ' ') - echo "$p $t" | tee -a ${file} - done - -} - -# Readers and writers should not starve each others. -fairness() { - # Check readers finished before writers. - # Find the time of the last read op. - # Count how many writes and how many read happend - # during that period, do the ratio. - true -} - -####################################################################### -# MAIN - -echo "Make sure debugfs is mounted on the device." -block_level -scalability -fairness - - diff --git a/tests/sdcard/sdcard_perf_test.cpp b/tests/sdcard/sdcard_perf_test.cpp deleted file mode 100644 index 7efa6508..00000000 --- a/tests/sdcard/sdcard_perf_test.cpp +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <cstdio> -#include <cstdlib> -#include <ctime> -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <limits.h> -#include <string.h> -#include <sys/stat.h> -#include <linux/fadvise.h> -#include <unistd.h> -#include <fts.h> - -#include "stopwatch.h" -#include "sysutil.h" -#include "testcase.h" - -// Stress test for the sdcard. Use this to generate some load on the -// sdcard and collect performance statistics. The output is either a -// human readable report or the raw timing samples that can be -// processed using another tool. -// -// Needs debugfs: -// adb root; -// adb shell mount -t debugfs none /sys/kernel/debug -// -// The following tests are defined (value of the --test flag): -// write: Open a file write some random data and close. -// read: Open a file read it and close. -// read_write: Combine readers and writers. -// open_create: Open|create an non existing file. -// -// For each run you can control how many processes will run the test in -// parallel to simulate a real load (--procnb flag) -// -// For each process, the test selected will be executed many time to -// get a meaningful average/min/max (--iterations flag) -// -// Use --dump to also get the raw data. -// -// For read/write tests, size is the number of Kbytes to use. -// -// To build: mmm system/extras/tests/sdcard/Android.mk SDCARD_TESTS=1 -// -// Examples: -// adb shell /system/bin/sdcard_perf_test --test=read --size=1000 --chunk-size=100 --procnb=1 --iterations=10 --dump > /tmp/data.txt -// adb shell /system/bin/sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump > /tmp/data.txt -// -// To watch the memory: cat /proc/meminfo -// If the phone crashes, look at /proc/last_kmsg on reboot. -// -// TODO: It would be cool if we could play with various fadvise() -// strategies in here to see how tweaking read-ahead changes things. -// - -extern char *optarg; -extern int optind, opterr, optopt; - -// TODO: No clue where fadvise is. Disabled for now. -#define FADVISE(fd, off, len, advice) (void)0 - -#ifndef min -#define min(a,b) (((a)>(b))?(b):(a)) -#endif - -namespace { -using android::kernelVersion; -using android::kMinKernelVersionBufferSize; -using android::schedFeatures; -using android::kMinSchedFeaturesBufferSize; -using android_test::StopWatch; -using android::writePidAndWaitForReply; -using android::waitForChildrenAndSignal; -using android::waitForChildrenOrExit; -using android_test::TestCase; - -const char *kAppName = "sdcard_perf_test"; -const char *kTestDir = "/sdcard/perf"; -const bool kVerbose = false; - -// Used by getopt to parse the command line. -struct option long_options[] = { - {"size", required_argument, 0, 's'}, - {"chunk-size", required_argument, 0, 'S'}, - {"depth", required_argument, 0, 'D'}, - {"iterations", required_argument, 0, 'i'}, - {"procnb", required_argument, 0, 'p'}, - {"test", required_argument, 0, 't'}, - {"dump", no_argument, 0, 'd'}, - {"cpu-scaling", no_argument, 0, 'c'}, - {"sync", required_argument, 0, 'f'}, - {"truncate", no_argument, 0, 'e'}, - {"no-new-fair-sleepers", no_argument, 0, 'z'}, - {"no-normalized-sleepers", no_argument, 0, 'Z'}, - {"fadvise", required_argument, 0, 'a'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0}, -}; - -void usage() -{ - printf("sdcard_perf_test --test=write|read|read_write|open_create|traverse [options]\n\n" - " -t --test: Select the test.\n" - " -s --size: Size in kbytes of the data.\n" - " -S --chunk-size: Size of a chunk. Default to size ie 1 chunk.\n" - " Data will be written/read using that chunk size.\n" - " -D --depth: Depth of directory tree to create for traversal.\n" - " -i --iterations: Number of time a process should carry its task.\n" - " -p --procnb: Number of processes to use.\n" - " -d --dump: Print the raw timing on stdout.\n" - " -c --cpu-scaling: Enable cpu scaling.\n" - " -s --sync: fsync|sync Use fsync or sync in write test. Default: no sync call.\n" - " -e --truncate: Truncate to size the file on creation.\n" - " -z --no-new-fair-sleepers: Turn them off. You need to mount debugfs.\n" - " -Z --no-normalized-sleepers: Turn them off. You need to mount debugfs.\n" - " -a --fadvise: Specify an fadvise policy (not supported).\n" - ); -} - -// Print command line, pid, kernel version, OOM adj and scheduler. -void printHeader(int argc, char **argv, const TestCase& testCase) -{ - printf("# Command: "); - for (int i = 0; i < argc; ++i) - { - printf("%s ", argv[i]); - } - printf("\n"); - - printf("# Pid: %d\n", getpid()); - - { - char buffer[kMinKernelVersionBufferSize] = {0, }; - if (kernelVersion(buffer, sizeof(buffer)) > 0) - { - printf("# Kernel: %s", buffer); - } - } - - // Earlier on, running this test was crashing the phone. It turned - // out that it was using too much memory but its oom_adj value was - // -17 which means disabled. -16 is the system_server and 0 is - // typically what applications run at. The issue is that adb runs - // at -17 and so is this test. We force oom_adj to 0 unless the - // oom_adj option has been used. - // TODO: We talked about adding an option to control oom_adj, not - // sure if we still need that. - int oomAdj = android::pidOutOfMemoryAdj(); - - printf("# Oom_adj: %d ", oomAdj); - if (oomAdj < 0) - { - android::setPidOutOfMemoryAdj(0); - printf("adjuted to %d", android::pidOutOfMemoryAdj()); - } - printf("\n"); - - { - char buffer[kMinSchedFeaturesBufferSize] = {0, }; - if (schedFeatures(buffer, sizeof(buffer)) > 0) - { - printf("# Sched features: %s", buffer); - } - } - printf("# Fadvise: %s\n", testCase.fadviseAsStr()); -} - -// Remove all the files under kTestDir and clear the caches. -void cleanup() { - android::resetDirectory(kTestDir); - android::syncAndDropCaches(); // don't pollute runs. -} - -// @param argc, argv have a wild guess. -// @param[out] testCase Structure built from the cmd line args. -void parseCmdLine(int argc, char **argv, TestCase *testCase)\ -{ - int c; - - while(true) - { - // getopt_long stores the option index here. - int option_index = 0; - - c = getopt_long (argc, argv, - "hS:s:D:i:p:t:dcf:ezZa:", - long_options, - &option_index); - // Detect the end of the options. - if (c == -1) break; - - switch (c) - { - case 's': - testCase->setDataSize(atoi(optarg) * 1024); - break; - case 'S': - testCase->setChunkSize(atoi(optarg) * 1024); - break; - case 'D': // tree depth - testCase->setTreeDepth(atoi(optarg)); - break; - case 'i': - testCase->setIter(atoi(optarg)); - printf("# Iterations: %d\n", testCase->iter()); - break; - case 'p': - testCase->setNproc(atoi(optarg)); - printf("# Proc nb: %d\n", testCase->nproc()); - break; - case 't': - testCase->setTypeFromName(optarg); - printf("# Test name %s\n", testCase->name()); - break; - case 'd': - testCase->setDump(); - break; - case 'c': - printf("# Cpu scaling is on\n"); - testCase->setCpuScaling(); - break; - case 'f': - if (strcmp("sync", optarg) == 0) { - testCase->setSync(TestCase::SYNC); - } else if (strcmp("fsync", optarg) == 0) { - testCase->setSync(TestCase::FSYNC); - } - break; - case 'e': // e for empty - printf("# Will truncate to size\n"); - testCase->setTruncateToSize(); - break; - case 'z': // no new fair sleepers - testCase->setNewFairSleepers(false); - break; - case 'Z': // no normalized sleepers - testCase->setNormalizedSleepers(false); - break; - case 'a': // fadvise - testCase->setFadvise(optarg); - break; - case 'h': - usage(); - exit(0); - default: - fprintf(stderr, "Unknown option %s\n", optarg); - exit(EXIT_FAILURE); - } - } -} - -// ---------------------------------------------------------------------- -// READ TEST - -// Read a file. We use a new file each time to avoid any caching -// effect that would happen if we were reading the same file each -// time. -// @param chunk buffer large enough where the chunk read are written. -// @param idx iteration number. -// @param testCase has all the timers and paramters to run the test. - -bool readData(char *const chunk, const int idx, TestCase *testCase) -{ - char filename[80] = {'\0',}; - - sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid()); - - testCase->openTimer()->start(); - int fd = open(filename, O_RDONLY); - testCase->openTimer()->stop(); - - if (fd < 0) - { - fprintf(stderr, "Open read only failed."); - return false; - } - FADVISE(fd, 0, 0, testCase->fadvise()); - - size_t left = testCase->dataSize(); - pid_t *pid = (pid_t*)chunk; - while (left > 0) - { - char *dest = chunk; - size_t chunk_size = testCase->chunkSize(); - - if (chunk_size > left) - { - chunk_size = left; - left = 0; - } - else - { - left -= chunk_size; - } - - testCase->readTimer()->start(); - while (chunk_size > 0) - { - ssize_t s = read(fd, dest, chunk_size); - if (s < 0) - { - fprintf(stderr, "Failed to read.\n"); - close(fd); - return false; - } - chunk_size -= s; - dest += s; - } - testCase->readTimer()->stop(); - } - close(fd); - if (testCase->pid() != *pid) - { - fprintf(stderr, "Wrong pid found @ read block %x != %x\n", testCase->pid(), *pid); - return false; - } - else - { - return true; - } -} - - -bool testRead(TestCase *testCase) { - // Setup the testcase by writting some dummy files. - const size_t size = testCase->dataSize(); - size_t chunk_size = testCase->chunkSize(); - char *const chunk = new char[chunk_size]; - - memset(chunk, 0xaa, chunk_size); - *((pid_t *)chunk) = testCase->pid(); // write our pid at the beginning of each chunk - - size_t iter = testCase->iter(); - - // since readers are much faster we increase the number of - // iteration to last longer and have concurrent read/write - // thoughout the whole test. - if (testCase->type() == TestCase::READ_WRITE) - { - iter *= TestCase::kReadWriteFactor; - } - - for (size_t i = 0; i < iter; ++i) - { - char filename[80] = {'\0',}; - - sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid()); - int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU); - - size_t left = size; - while (left > 0) - { - if (chunk_size > left) - { - chunk_size = left; - } - ssize_t written = write(fd, chunk, chunk_size); - if (written < 0) - { - fprintf(stderr, "Write failed %d %s.", errno, strerror(errno)); - return false; - } - left -= written; - } - close(fd); - } - if (kVerbose) printf("Child %d all chunk written\n", testCase->pid()); - - android::syncAndDropCaches(); - testCase->signalParentAndWait(); - - // Start the read test. - testCase->testTimer()->start(); - for (size_t i = 0; i < iter; ++i) - { - if (!readData(chunk, i, testCase)) - { - return false; - } - } - testCase->testTimer()->stop(); - - delete [] chunk; - return true; -} - -// ---------------------------------------------------------------------- -// WRITE TEST - -bool writeData(const char *const chunk, const int idx, TestCase *testCase) { - char filename[80] = {'\0',}; - - sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid()); - testCase->openTimer()->start(); - int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU); // no O_TRUNC, see header comment - testCase->openTimer()->stop(); - - if (fd < 0) - { - fprintf(stderr, "Open write failed."); - return false; - } - FADVISE(fd, 0, 0, testCase->fadvise()); - - if (testCase->truncateToSize()) - { - testCase->truncateTimer()->start(); - ftruncate(fd, testCase->dataSize()); - testCase->truncateTimer()->stop(); - } - - size_t left = testCase->dataSize(); - while (left > 0) - { - const char *dest = chunk; - size_t chunk_size = testCase->chunkSize(); - - if (chunk_size > left) - { - chunk_size = left; - left = 0; - } - else - { - left -= chunk_size; - } - - - testCase->writeTimer()->start(); - while (chunk_size > 0) - { - ssize_t s = write(fd, dest, chunk_size); - if (s < 0) - { - fprintf(stderr, "Failed to write.\n"); - close(fd); - return false; - } - chunk_size -= s; - dest += s; - } - testCase->writeTimer()->stop(); - } - - if (TestCase::FSYNC == testCase->sync()) - { - testCase->syncTimer()->start(); - fsync(fd); - testCase->syncTimer()->stop(); - } - else if (TestCase::SYNC == testCase->sync()) - { - testCase->syncTimer()->start(); - sync(); - testCase->syncTimer()->stop(); - } - close(fd); - return true; -} - -bool testWrite(TestCase *testCase) -{ - const size_t size = testCase->dataSize(); - size_t chunk_size = testCase->chunkSize(); - char *data = new char[chunk_size]; - - memset(data, 0xaa, chunk_size); - // TODO: write the pid at the beginning like in the write - // test. Have a mode where we check the write was correct. - testCase->signalParentAndWait(); - - testCase->testTimer()->start(); - for (size_t i = 0; i < testCase->iter(); ++i) - { - if (!writeData(data, i, testCase)) - { - return false; - } - } - testCase->testTimer()->stop(); - delete [] data; - return true; -} - - -// ---------------------------------------------------------------------- -// READ WRITE - -// Mix of read and write test. Even PID run the write test. Odd PID -// the read test. Not fool proof but work most of the time. -bool testReadWrite(TestCase *testCase) -{ - if (getpid() & 0x1) { - return testRead(testCase); - } else { - return testWrite(testCase); - } -} - -// ---------------------------------------------------------------------- -// OPEN CREATE TEST - -bool testOpenCreate(TestCase *testCase) -{ - char filename[80] = {'\0',}; - - testCase->signalParentAndWait(); - testCase->testTimer()->start(); - - for (size_t i = 0; i < testCase->iter(); ++i) - { - sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid()); - - int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU); - FADVISE(fd, 0, 0, testCase->fadvise()); - - if (testCase->truncateToSize()) - { - ftruncate(fd, testCase->dataSize()); - } - if (fd < 0) - { - return false; - } - close(fd); - } - testCase->testTimer()->stop(); - return true; -} - -bool writeTestFile(TestCase *testCase, const char* filename) { - int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU); - if (fd < 0) { - fprintf(stderr, "open() failed: %s\n", strerror(errno)); - return false; - } - - bool res = false; - - char * const chunk = new char[testCase->chunkSize()]; - memset(chunk, 0xaa, testCase->chunkSize()); - - size_t left = testCase->dataSize(); - while (left > 0) { - char *dest = chunk; - size_t chunk_size = testCase->chunkSize(); - - if (chunk_size > left) { - chunk_size = left; - left = 0; - } else { - left -= chunk_size; - } - - while (chunk_size > 0) { - ssize_t s = write(fd, dest, chunk_size); - if (s < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - goto fail; - } - chunk_size -= s; - dest += s; - } - } - - res = true; -fail: - close(fd); - delete[] chunk; - return res; -} - -// ---------------------------------------------------------------------- -// TRAVERSE - -#define MAX_PATH 512 - -// Creates a directory tree that is both deep and wide, and times -// traversal using fts_open(). -bool testTraverse(TestCase *testCase) { - char path[MAX_PATH]; - char filepath[MAX_PATH]; - strcpy(path, kTestDir); - - // Generate a deep directory hierarchy - size_t depth = testCase->treeDepth(); - for (size_t i = 0; i < depth; i++) { - // Go deeper by appending onto current path - snprintf(path + strlen(path), MAX_PATH - strlen(path), "/dir%d", i); - mkdir(path, S_IRWXU); - - // Create some files at this depth - strcpy(filepath, path); - int pathlen = strlen(path); - char* nameStart = filepath + pathlen; - for (size_t j = 0; j < depth; j++) { - snprintf(nameStart, MAX_PATH - pathlen, "/file%d", j); - writeTestFile(testCase, filepath); - } - } - - testCase->signalParentAndWait(); - testCase->testTimer()->start(); - - // Now traverse structure - size_t iter = testCase->iter(); - for (size_t i = 0; i < iter; i++) { - testCase->traverseTimer()->start(); - - FTS *ftsp; - if ((ftsp = fts_open((char **) &kTestDir, FTS_LOGICAL | FTS_XDEV, NULL)) == NULL) { - fprintf(stderr, "fts_open() failed: %s\n", strerror(errno)); - return false; - } - - // Count discovered files - int dirs = 0, files = 0; - - FTSENT *curr; - while ((curr = fts_read(ftsp)) != NULL) { - switch (curr->fts_info) { - case FTS_D: - dirs++; - break; - case FTS_F: - files++; - break; - } - } - - fts_close(ftsp); - - testCase->traverseTimer()->stop(); - - int expectedDirs = depth + 1; - if (expectedDirs != dirs) { - fprintf(stderr, "expected %d dirs, but found %d\n", expectedDirs, dirs); - return false; - } - - int expectedFiles = depth * depth; - if (expectedFiles != files) { - fprintf(stderr, "expected %d files, but found %d\n", expectedFiles, files); - return false; - } - } - - testCase->testTimer()->stop(); - return true; -} - -} // anonymous namespace - -int main(int argc, char **argv) -{ - android_test::TestCase testCase(kAppName); - - cleanup(); - - parseCmdLine(argc, argv, &testCase); - printHeader(argc, argv, testCase); - - printf("# File size %d kbytes\n", testCase.dataSize() / 1024); - printf("# Chunk size %d kbytes\n", testCase.chunkSize() / 1024); - printf("# Sync: %s\n", testCase.syncAsStr()); - - if (!testCase.cpuScaling()) - { - android::disableCpuScaling(); - } - - switch(testCase.type()) { - case TestCase::WRITE: - testCase.mTestBody = testWrite; - break; - case TestCase::READ: - testCase.mTestBody = testRead; - break; - case TestCase::OPEN_CREATE: - testCase.mTestBody = testOpenCreate; - break; - case TestCase::READ_WRITE: - testCase.mTestBody = testReadWrite; - break; - case TestCase::TRAVERSE: - testCase.mTestBody = testTraverse; - break; - default: - fprintf(stderr, "Unknown test type %s", testCase.name()); - exit(EXIT_FAILURE); - } - - testCase.createTimers(); - - bool ok; - - ok = testCase.runTest(); - - cleanup(); - if (!ok) - { - printf("error %d %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - else - { - exit(EXIT_SUCCESS); - } -} diff --git a/tests/sdcard/stopwatch.cpp b/tests/sdcard/stopwatch.cpp deleted file mode 100644 index 77768d69..00000000 --- a/tests/sdcard/stopwatch.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -#include <malloc.h> -#include <stdio.h> -#include <time.h> -#include "stopwatch.h" -#include <math.h> - -#define SNPRINTF_OR_RETURN(str, size, format, ...) { \ - int len = snprintf((str), (size), (format), ## __VA_ARGS__); \ - if (len < 0) return; \ - if (len > static_cast<int>(size)) { \ - fprintf(stderr, "Not enough space\n"); \ - return; \ - } else { \ - (size) -= len; (str) += len; \ - } \ - } - -namespace { -const bool kVerbose = false; -bool printRaw = false; -} - -namespace android_test { - -StopWatch::StopWatch(const char *name, size_t capacity) - : mName(strdup(name)), mNum(0), mData(NULL), mDataLen(0), mCapacity(capacity * 2), - mSizeKbytes(0), mAlreadyPrinted(false), mPrintRaw(false), - mDuration(0.0), mDeviation(0.0), - mMinDuration(0.0), mMinIdx(0), - mMaxDuration(0.0), mMaxIdx(0), - mDeltas(NULL), mUsed(false) -{ - mStart.tv_sec = 0; - mStart.tv_nsec = 0; - mData = (Measurement *) malloc(mCapacity * sizeof(Measurement)); -} - -StopWatch::~StopWatch() -{ - if (mUsed && !mAlreadyPrinted) - { - fprintf(stderr, "Discarding data for %s\n", mName); - } - free(mData); - free(mName); - delete [] mDeltas; -} - -void StopWatch::start() -{ - checkCapacity(); - clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime); - mData[mDataLen].mIsStart = true; - if (!mUsed) - { - mStart = mData[mDataLen].mTime; // mDataLen should be 0 - mUsed = true; - } - ++mNum; - ++mDataLen; -} - -void StopWatch::stop() -{ - checkCapacity(); - clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime); - mData[mDataLen].mIsStart = false; - ++mDataLen; -} - -void StopWatch::setPrintRawMode(bool raw) -{ - printRaw = raw; -} - - -void StopWatch::sprint(char **str, size_t *size) -{ - if (kVerbose) fprintf(stderr, "printing\n"); - mAlreadyPrinted = true; - if (0 == mDataLen) - { - return; - } - if (mDataLen > 0 && mData[mDataLen - 1].mIsStart) - { - stop(); - } - if (kVerbose) SNPRINTF_OR_RETURN(*str, *size, "# Got %d samples for %s\n", mDataLen, mName); - processSamples(); - - SNPRINTF_OR_RETURN(*str, *size, "# StopWatch %s total/cumulative duration %f Samples: %d\n", - mName, mDuration, mNum); - printThroughput(str, size); - printAverageMinMax(str, size); - - if (printRaw) - { - // print comment header and summary values. - - SNPRINTF_OR_RETURN(*str, *size, "# Name Iterations Duration Min MinIdx Max MaxIdx SizeKbytes\n"); - SNPRINTF_OR_RETURN(*str, *size, "%s %d %f %f %d %f %d %d\n", mName, mNum, mDuration, - mMinDuration, mMinIdx, mMaxDuration, mMaxIdx, mSizeKbytes); - // print each duration sample - for (size_t i = 0; i < mDataLen / 2; ++i) - { - long second = mData[i * 2].mTime.tv_sec - mStart.tv_sec; - long nano = mData[i * 2].mTime.tv_nsec - mStart.tv_nsec; - - SNPRINTF_OR_RETURN(*str, *size, "%f %f\n", double(second) + double(nano) / 1.0e9, mDeltas[i]); - } - } - -} - -// Normally we should have enough capacity but if we have to -// reallocate the measurement buffer (e.g start and stop called more -// than once in an iteration) we let the user know. She should provide -// a capacity when building the StopWatch. -void StopWatch::checkCapacity() -{ - if (mDataLen >= mCapacity) - { - mCapacity *= 2; - fprintf(stderr, "# Increased capacity to %d for %s. Measurement affected.\n", - mCapacity, mName); - mData = (Measurement *)realloc(mData, mCapacity * sizeof(Measurement)); - } -} - - -// Go over all the samples and compute the diffs between a start and -// stop pair. The diff is accumulated in mDuration and inserted in -// mDeltas. -// The min and max values for a diff are also tracked. -void StopWatch::processSamples() -{ - if (kVerbose) fprintf(stderr, "processing samples\n"); - size_t n = mDataLen / 2; - mDeltas= new double[n]; - for (size_t i = 0; i < mDataLen; i += 2) // even: start odd: stop - { - long second = mData[i + 1].mTime.tv_sec - mData[i].mTime.tv_sec; - long nano = mData[i + 1].mTime.tv_nsec - mData[i].mTime.tv_nsec; - - mDeltas[i / 2] = double(second) + double(nano) / 1.0e9; - } - - for (size_t i = 0; i < n; ++i) - { - if (0 == i) - { - mMinDuration = mMaxDuration = mDeltas[i]; - } - else - { - if (mMaxDuration < mDeltas[i]) - { - mMaxDuration = mDeltas[i]; - mMaxIdx = i; - } - if (mMinDuration > mDeltas[i]) - { - mMinDuration = mDeltas[i]; - mMinIdx = i; - } - } - mDuration += mDeltas[i]; - } - double avgDuration = mDuration / n; - double diffSQ = 0.0; - for (size_t i = 0; i < n; ++i) - { - diffSQ += pow((mDeltas[i] - avgDuration), 2.0); - } - mDeviation = sqrt(diffSQ / n); -} - - -double StopWatch::timespecToDouble(const struct timespec& time) -{ - double val = double(time.tv_nsec) / 1.0e9 + double(time.tv_sec); - return val < 0.0 ? -val : val; // sometimes 0.00 is -0.00 -} - - -// If we have only 2 values, don't bother printing anything. -void StopWatch::printAverageMinMax(char **str, size_t *size) -{ - if (mDataLen > 2) // if there is only one sample, avg, min, max are trivial. - { - SNPRINTF_OR_RETURN(*str, *size, "# Average %s duration %f s/op\n", mName, mDuration / mNum); - SNPRINTF_OR_RETURN(*str, *size, "# Standard deviation %s duration %f \n", mName, mDeviation); - SNPRINTF_OR_RETURN(*str, *size, "# Min %s duration %f [%d]\n", mName, mMinDuration, mMinIdx); - SNPRINTF_OR_RETURN(*str, *size, "# Max %s duration %f [%d]\n", mName, mMaxDuration, mMaxIdx); - } -} - -void StopWatch::printThroughput(char **str, size_t *size) -{ - if (0 != mSizeKbytes) - { - SNPRINTF_OR_RETURN(*str, *size, "# Size: %d Kbytes Total: %d\n", mSizeKbytes, mNum); - SNPRINTF_OR_RETURN(*str, *size, "# Speed %f Kbyte/s\n", double(mSizeKbytes) * mNum / mDuration); - } -} -} // namespace android_test diff --git a/tests/sdcard/stopwatch.h b/tests/sdcard/stopwatch.h deleted file mode 100644 index c54f2576..00000000 --- a/tests/sdcard/stopwatch.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ -#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ - -#include <stdlib.h> -#include <stdio.h> -#include <time.h> - -namespace android_test { - -// StopWatch class to collect execution statistics. -// -// Once the watch has been created, start and stop can be called to -// capture an event duration. -// -// On completion, use 'sprint' to retrieve the data. -// -// If StopWatch::setPrintRawMode(true) has been called, the raw -// samples also are printed. -// The print method is thread safe to avoid mixing the result of -// watches on different threads. For processes, use different files -// that you concat after the run. -// -// If the time measure is associated with some volume of data, use -// setMbytes, the print method will compute the average throughput -// based on that value. -// -// To capture the time accurately and since the runs are not too long, -// we collect the raw start and stop time in an array that get -// processed once all the measurements have been done. -// -// Typical Usage: -// ============== -// -// StopWatch watch("my name", 20); -// -// for (int i = 0; i < 20; ++i) { -// watch.start(); -// doMyStuff(); -// watch.stop(); -// } -// char buffer[4096]; -// char *str = buffer; -// size_t size = sizeof(buffer); -// watch.sprint(&str, &size); -// - -class StopWatch { - public: - // Time of the snapshot and its nature (start of the interval or end of it). - struct Measurement { - struct timespec mTime; - bool mIsStart; - }; - static const size_t kUseDefaultCapacity = 20; - - // Create a stop watch. Default capacity == 2 * interval_nb - // @param name To be used when the results are displayed. No - // spaces, use _ instead. - // @param capacity Hint about the number of sampless that will be - // measured (1 sample == 1 start + 1 stop). Used - // to size the internal storage, when the capacity - // is reached, it is doubled. - StopWatch(const char *name, size_t capacity = kUseDefaultCapacity); - ~StopWatch(); - - // A StopWatch instance measures time intervals. Use setDataSize - // if some volume of data is processed during these intervals, to - // get the average throughput (in kbytes/s) printed. - void setDataSize(size_t size_in_bytes) { mSizeKbytes = size_in_bytes / 1000; } - - // Starts and stops the timer. The time between the 2 calls is an - // interval whose duration will be reported in sprint. - void start(); - void stop(); - - // Print a summary of the measurement and optionaly the raw data. - // The summary is commented out using a leading '#'. The raw data - // is a pair (time, duration). The 1st sample is always at time - // '0.0'. - // @param str[inout] On entry points to the begining of a buffer - // where to write the data. On exit points pass the last byte - // written. - // @param size[inout] On entry points to the size of the buffer - // pointed by *str. On exit *size is the amount of free space left - // in the buffer. If there was not enough space the data is truncated - // and a warning is printed. - void sprint(char **str, size_t *size); - - // @return true if at least one interval was timed. - bool used() const { return mUsed; } - - // Affects all the timers. Instructs all the timers to print the - // raw data as well as the summary. - static void setPrintRawMode(bool printRaw); - - private: - void checkCapacity(); - double timespecToDouble(const struct timespec& time); - void printAverageMinMax(char **str, size_t *size); - void printThroughput(char **str, size_t *size); - // Allocate mDeltas and fill it in. Search for the min and max. - void processSamples(); - - char *const mName; // Name of the test. - struct timespec mStart; - size_t mNum; // # of intervals == # of start() calls. - struct Measurement *mData; - size_t mDataLen; - size_t mCapacity; - int mSizeKbytes; - - bool mAlreadyPrinted; - bool mPrintRaw; - - double mDuration; - double mDeviation; - double mMinDuration; - size_t mMinIdx; - double mMaxDuration; - size_t mMaxIdx; - double *mDeltas; - - bool mUsed; -}; - -} // namespace android_test - -#endif // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ diff --git a/tests/sdcard/sysutil.cpp b/tests/sdcard/sysutil.cpp deleted file mode 100644 index 0182590a..00000000 --- a/tests/sdcard/sysutil.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include "sysutil.h" - -namespace { -const int kError = -1; -// Max number of retries on EAGAIN and EINTR. Totally arbitrary. -const int kMaxAttempts = 8; - -// How long to wait after a cache purge. A few seconds (arbitrary). -const int kCachePurgeSleepDuration = 2; // seconds - -const bool kSilentIfMissing = false; - -const char *kKernelVersion = "/proc/version"; -const char *kScalingGovernorFormat = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor"; -const char *kDropCaches = "/proc/sys/vm/drop_caches"; -const char *kSchedFeatures = "/sys/kernel/debug/sched_features"; -const char *kNewFairSleepers = "NEW_FAIR_SLEEPERS"; -const char *kNoNewFairSleepers = "NO_NEW_FAIR_SLEEPERS"; -const char *kNormalizedSleepers = "NORMALIZED_SLEEPER"; // no 's' at the end -const char *kNoNormalizedSleepers = "NO_NORMALIZED_SLEEPER"; - -const char *kDebugfsWarningMsg = "Did you 'adb root; adb shell mount -t debugfs none /sys/kernel/debug' ?"; - -// TODO: Surely these file utility functions must exist already. A -// quick grep did not turn up anything. Look harder later. - -void printErrno(const char *msg, const char *filename) -{ - fprintf(stderr, "# %s %s %d %s\n", msg, filename, errno, strerror(errno)); -} - -// Read a C-string from a file. If the buffer is too short, an error -// message will be printed on stderr. -// @param filename Of the file to read. -// @param start Buffer where the data should be written to. -// @param size The size of the buffer pointed by str. Must be >= 1. -// @return The number of characters read (not including the trailing'\0' used -// to end the string) or -1 if there was an error. -int readStringFromFile(const char *filename, char *const start, size_t size, bool must_exist=true) -{ - if (NULL == start || size == 0) - { - return 0; - } - char *end = start; - int fd = open(filename, O_RDONLY); - - if (fd < 0) - { - if (ENOENT != errno || must_exist) - { - printErrno("Failed to open", filename); - } - return kError; - } - - bool eof = false; - bool error = false; - int attempts = 0; - - --size; // reserve space for trailing '\0' - - while (size > 0 && !error && !eof && attempts < kMaxAttempts) - { - ssize_t s; - - s = read(fd, end, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to read", filename); - } - } - else if (0 == s) - { - eof = true; - } - else - { - end += s; - size -= s; - } - ++attempts; - } - - close(fd); - - if (error) - { - return kError; - } - else - { - *end = '\0'; - if (!eof) - { - fprintf(stderr, "Buffer too small for %s\n", filename); - } - return end - start; - } -} - -// Write a C string ('\0' terminated) to a file. -// -int writeStringToFile(const char *filename, const char *start, bool must_exist=true) -{ - int fd = open(filename, O_WRONLY); - - - if (fd < 0) - { - if (ENOENT != errno || must_exist) - { - printErrno("Failed to open", filename); - } - return kError; - } - - const size_t len = strlen(start); - size_t size = len; - bool error = false; - int attempts = 0; - - while (size > 0 && !error && attempts < kMaxAttempts) - { - ssize_t s = write(fd, start, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to write", filename); - } - } - else - { - start += s; - size -= s; - } - ++attempts; - } - close(fd); - - if (error) - { - return kError; - } - else - { - if (size > 0) - { - fprintf(stderr, "Partial write to %s (%d out of %d)\n", - filename, size, len); - } - return len - size; - } -} - -int writeIntToFile(const char *filename, long value) -{ - char buffer[16] = {0,}; - sprintf(buffer, "%ld", value); - return writeStringToFile(filename, buffer); -} - -// @return a message describing the reason why the child exited. The -// message is in a shared buffer, not thread safe, erased by -// subsequent calls. -const char *reasonChildExited(int status) -{ - static char buffer[80]; - - if (WIFEXITED(status)) - { - snprintf(buffer, sizeof(buffer), "ok (%d)", WEXITSTATUS(status)); - } - else if (WIFSIGNALED(status)) - { - snprintf(buffer, sizeof(buffer), "signaled (%d %s)", WTERMSIG(status), strsignal(WTERMSIG(status))); - } - else - { - snprintf(buffer, sizeof(buffer), "stopped?"); - } - return buffer; -} - - -} // anonymous namespace - -namespace android { - -int kernelVersion(char *str, size_t size) -{ - return readStringFromFile(kKernelVersion, str, size); -} - -int pidOutOfMemoryAdj() -{ - char filename[FILENAME_MAX]; - - snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); - - char value[16]; - if (readStringFromFile(filename, value, sizeof(value)) == -1) - { - return -127; - } - else - { - return atoi(value); - } -} - -void setPidOutOfMemoryAdj(int level) -{ - char filename[FILENAME_MAX]; - - snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); - writeIntToFile(filename, level); -} - -void disableCpuScaling() -{ - for (int cpu = 0; cpu < 16; ++cpu) // 16 cores mobile phones, abestos pockets recommended. - { - char governor[FILENAME_MAX]; - sprintf(governor, kScalingGovernorFormat, cpu); - - if (writeStringToFile(governor, "performance", kSilentIfMissing) < 0) - { - if (cpu > 0 && errno == ENOENT) - { - break; // cpu1 or above not found, ok since we have cpu0. - } - fprintf(stderr, "Failed to write to scaling governor file for cpu %d: %d %s", - cpu, errno, strerror(errno)); - break; - } - } -} - -int schedFeatures(char *str, size_t size) -{ - return readStringFromFile(kSchedFeatures, str, size); -} - -bool newFairSleepers() -{ - char value[256] = {0,}; - - if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) - { - printErrno(kDebugfsWarningMsg, kSchedFeatures); - return false; - } - return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; -} - -void setNewFairSleepers(bool on) -{ - int retcode; - - if (on) - { - retcode = writeStringToFile(kSchedFeatures, kNewFairSleepers); - } - else - { - retcode = writeStringToFile(kSchedFeatures, kNoNewFairSleepers); - } - if (retcode < 0) - { - fprintf(stderr, "# %s\n", kDebugfsWarningMsg); - } -} - -bool normalizedSleepers() -{ - char value[256] = {0,}; - - if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) - { - printErrno(kDebugfsWarningMsg, kSchedFeatures); - return false; - } - return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; -} - -void setNormalizedSleepers(bool on) -{ - int retcode; - - if (on) - { - retcode = writeStringToFile(kSchedFeatures, kNormalizedSleepers); - } - else - { - retcode = writeStringToFile(kSchedFeatures, kNoNormalizedSleepers); - } - if (retcode < 0) - { - fprintf(stderr, "# %s\n", kDebugfsWarningMsg); - } -} - -pid_t forkOrExit() -{ - pid_t childpid = fork(); - - if (-1 == childpid) - { - fprintf(stderr, "Fork failed: %d %s", errno, strerror(errno)); - exit(EXIT_FAILURE); - } - return childpid; -} - -void waitForChildrenOrExit(int num) -{ - while (num > 0) - { - int status; - pid_t pid = wait(&status); - if (-1 == pid) - { - fprintf(stderr, "Wait failed\n"); - } - else - { - if (!WIFEXITED(status)) - { - fprintf(stderr, "Child pid %d did not exit cleanly %s\n", - pid, reasonChildExited(status)); - exit(EXIT_FAILURE); - } - } - --num; - } -} - -// Sync and cache cleaning functions. In the old hpux days I was told -// to always call *sync twice. The same advice seems to be still true -// today so *sync is called twice. -// Also we wait 'a little' to give a chance to background threads to -// purge their caches. -void syncAndDropCaches(int code) -{ - sync(); - sync(); - writeIntToFile(kDropCaches, code); - sleep(kCachePurgeSleepDuration); -} - - -void fsyncAndDropCaches(int fd, int code) -{ - fsync(fd); - fsync(fd); - writeIntToFile(kDropCaches, code); - sleep(kCachePurgeSleepDuration); -} - - -void resetDirectory(const char *directory) -{ - DIR *dir = opendir(directory); - - if (NULL != dir) - { - struct dirent *entry; - char name_buffer[PATH_MAX]; - - while((entry = readdir(dir))) - { - if (0 == strcmp(entry->d_name, ".") - || 0 == strcmp(entry->d_name, "..") - || 0 == strcmp(entry->d_name, "lost+found")) - { - continue; - } - strcpy(name_buffer, directory); - strcat(name_buffer, "/"); - strcat(name_buffer, entry->d_name); - unlink(name_buffer); - } - closedir(dir); - } else { - mkdir(directory, S_IRWXU); - } -} - - -// IPC -bool writePidAndWaitForReply(int writefd, int readfd) -{ - if (writefd > readfd) - { - fprintf(stderr, "Called with args in wrong order!!\n"); - return false; - } - pid_t pid = getpid(); - char *start = reinterpret_cast<char *>(&pid); - size_t size = sizeof(pid); - bool error = false; - int attempts = 0; - - while (size > 0 && !error && attempts < kMaxAttempts) - { - ssize_t s = write(writefd, start, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to write", "parent"); - } - } - else - { - start += s; - size -= s; - } - ++attempts; - } - - if (error || 0 != size) - { - return false; - } - - bool eof = false; - char dummy; - size = sizeof(dummy); - error = false; - attempts = 0; - - while (size > 0 && !error && !eof && attempts < kMaxAttempts) - { - ssize_t s; - - s = read(readfd, &dummy, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to read", "parent"); - } - } - else if (0 == s) - { - eof = true; - } - else - { - size -= s; - } - ++attempts; - } - if (error || 0 != size) - { - return false; - } - return true; -} - - - -bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd) -{ - if (readfd > writefd) - { - fprintf(stderr, "Called with args in wrong order!!\n"); - return false; - } - - bool error; - int attempts; - size_t size; - - for (int p = 0; p < mProcessNb; ++p) - { - bool eof = false; - pid_t pid; - char *end = reinterpret_cast<char *>(&pid); - - error = false; - attempts = 0; - size = sizeof(pid); - - while (size > 0 && !error && !eof && attempts < kMaxAttempts) - { - ssize_t s; - - s = read(readfd, end, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to read", "child"); - } - } - else if (0 == s) - { - eof = true; - } - else - { - end += s; - size -= s; - } - ++attempts; - } - - if (error || 0 != size) - { - return false; - } - } - - for (int p = 0; p < mProcessNb; ++p) - { - char dummy; - - error = false; - attempts = 0; - size = sizeof(dummy); - - while (size > 0 && !error && attempts < kMaxAttempts) - { - ssize_t s = write(writefd, &dummy, size); - - if (s < 0) - { - error = EAGAIN != errno && EINTR != errno; - if (error) - { - printErrno("Failed to write", "child"); - } - } - else - { - size -= s; - } - ++attempts; - } - - if (error || 0 != size) - { - return false; - } - } - return true; -} - -} // namespace android diff --git a/tests/sdcard/sysutil.h b/tests/sdcard/sysutil.h deleted file mode 100644 index 3df79c12..00000000 --- a/tests/sdcard/sysutil.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ -#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ - -#include <stdlib.h> -namespace android { - -// Collection of functions to access the system: -// .kernelVersion Retrieve the full kernel description. -// .pidOutOfMemoryAdj Get and set the OOM adj value. -// .setPidOutOfMemoryAdj -// .schedFeatures Manipulate the scheduler using debugfs. -// .newFairSleepers -// .setNewFairSleepers -// .disableCpuScaling Set cpu scaling to 'performance'. -// .forkOrExit Fork a child or exit. -// .syncAnddropCaches Call sync an drop page/dentries/inodes caches. -// .fsyncAnddropCaches Call fsync an drop page/dentries/inodes caches. -// .resetDirectory Delete (non-recursive) files in a directory. -// -// IPC function to synchonize a processes with their parent. -// .writePidAndWaitForReply To instruct the parent the child is ready. -// Blocks until the parent signals back. -// .waitForChildrenAndSignal Blocks until all the children have called -// writePidAndWaitForReply. -// Then unblock all the children. -// .waitForChildrenOrExit Wait and exit if a child exit with errors. -// - -// Minimum size for the buffer to retrieve the kernel version. -static const size_t kMinKernelVersionBufferSize = 256; - -// @param str points to the buffer where the kernel version should be -// added. Must be at least kMinKernelVersionBufferSize chars. -// @param size of the buffer pointed by str. -// @return If successful the number of characters inserted in the -// buffer (not including the trailing '\0' byte). -1 otherwise. -int kernelVersion(char *str, size_t size); - - -// Return the out of memory adj for this process. /proc/<pid>/oom_adj. -// @return the oom_adj of the current process. Typically: -// 0: a regular process. Should die on OOM. -// -16: system_server level. -// -17: disable, this process will never be killed. -// -127: error. -int pidOutOfMemoryAdj(); -void setPidOutOfMemoryAdj(int level); - -// Disable cpu scaling. -void disableCpuScaling(); - - -// Minimum size for the buffer to retrieve the sched features. -static const size_t kMinSchedFeaturesBufferSize = 256; - -// @param str points to the buffer where the sched features should be -// added. Must be at least kMinSchedFeaturesBufferSize chars. -// @param size of the buffer pointed by str. -// @return If successful the number of characters inserted in the -// buffer (not including the trailing '\0' byte). -1 otherwise. -int schedFeatures(char *str, size_t size); - -// @return true if NEW_FAIR_SLEEPERS is set, false if NO_NEW_FAIR_SLEEPERS is set. -bool newFairSleepers(); - -// Turns NEW_FAIR_SLEEPERS on or off. -void setNewFairSleepers(bool on); - -// @return true if NORMALIZED_SLEEPERS is set, false if NO_NORMALIZED_SLEEPERS is set. -bool normalizedSleepers(); - -// Turns NORMALIZED_SLEEPERS on or off. -void setNormalizedSleepers(bool on); - -// Filesystem - -// Sync and drop caches. Sync is needed because dirty objects are not -// freable. -// @param code: -// * 1 To free pagecache. -// * 2 To free dentries and inodes. -// * 3 To free pagecache, dentries and inodes. -void syncAndDropCaches(int code = 3); - -// Fsync the given fd and drop caches. Fsync is needed because dirty -// objects are not freable. -// @param code: -// * 1 To free pagecache. -// * 2 To free dentries and inodes. -// * 3 To free pagecache, dentries and inodes. -void fsyncAndDropCaches(int fd, int code = 3); - -// Delete all the files in the given directory. If the directory does -// not exist, it is created. Use this at the beginning of a test to -// make sure you have a clean existing directory, previous run may -// have crashed and left clutter around. -void resetDirectory(const char *directory); - -// IPC - -// Try to fork. exit on failure. -pid_t forkOrExit(); - -// Signal our parent we are alive and ready by sending our pid. -// Then do a blocking read for parent's reply. -bool writePidAndWaitForReply(int writefd, int readfd); - -// Wait for all the children to report their pids. -// Then unblock them. -bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd); - -// Wait for 'num' children to complete. -// If a child did not exit cleanly, exit. -void waitForChildrenOrExit(int num); - -} // namespace android - -#endif // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ diff --git a/tests/sdcard/testcase.cpp b/tests/sdcard/testcase.cpp deleted file mode 100644 index 06fd71b3..00000000 --- a/tests/sdcard/testcase.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "testcase.h" -#include <hardware_legacy/power.h> // wake lock -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <linux/fadvise.h> - -namespace { -const bool kVerbose = false; -} - -namespace android_test { - -TestCase::TestCase(const char *appName) - : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000), - mChunkSize(mDataSize), mTreeDepth(8), mIter(20), mNproc(1), - mType(UNKNOWN_TEST), mDump(false), mCpuScaling(false), - mSync(NO_SYNC), mFadvice(POSIX_FADV_NORMAL), mTruncateToSize(false), - mTestTimer(NULL) -{ - // Make sure the cpu and phone are fully awake. The - // FULL_WAKE_LOCK was used by java apps and don't do - // anything. Also the partial wake lock is a nop if the phone - // is plugged in via USB. - acquire_wake_lock(PARTIAL_WAKE_LOCK, mAppName); - mPid = getpid(); - setNewFairSleepers(true); - setNormalizedSleepers(true); - if (pipe(mIpc) < 0) - { - fprintf(stderr, "pipe failed\n"); - exit(1); - } - if (pipe(mIpc + 2) < 0) - { - fprintf(stderr, "pipe failed\n"); - exit(1); - } -} - -TestCase::~TestCase() -{ - release_wake_lock(mAppName); - for (int i = 0; i < 4; ++i) close(mIpc[i]); - delete mTestTimer; - delete mOpenTimer; -} - - -bool TestCase::runTest() -{ - if (UNKNOWN_TEST == mType) - { - fprintf(stderr, "No test set."); - return false; - } - for (size_t p = 0; p < mNproc; ++p) - { - pid_t childpid = android::forkOrExit(); - - if (0 == childpid) { // I am a child, run the test. - mPid = getpid(); - close(mIpc[READ_FROM_CHILD]); - close(mIpc[WRITE_TO_CHILD]); - - if (kVerbose) printf("Child pid: %d\n", mPid); - if (!mTestBody(this)) { - printf("Test failed\n"); - } - char buffer[32000] = {0,}; - char *str = buffer; - size_t size_left = sizeof(buffer); - - testTimer()->sprint(&str, &size_left); - if(openTimer()->used()) openTimer()->sprint(&str, &size_left); - if(readTimer()->used()) readTimer()->sprint(&str, &size_left); - if(writeTimer()->used()) writeTimer()->sprint(&str, &size_left); - if(syncTimer()->used()) syncTimer()->sprint(&str, &size_left); - if(truncateTimer()->used()) truncateTimer()->sprint(&str, &size_left); - if(traverseTimer()->used()) traverseTimer()->sprint(&str, &size_left); - - write(mIpc[TestCase::WRITE_TO_PARENT], buffer, str - buffer); - - - close(mIpc[WRITE_TO_PARENT]); - close(mIpc[READ_FROM_PARENT]); - exit(EXIT_SUCCESS); - } - } - // I am the parent process - close(mIpc[WRITE_TO_PARENT]); - close(mIpc[READ_FROM_PARENT]); - - // Block until all the children have reported for - // duty. Unblock them so they start the work. - if (!android::waitForChildrenAndSignal(mNproc, mIpc[READ_FROM_CHILD], mIpc[WRITE_TO_CHILD])) - { - exit(1); - } - - // Process the output of each child. - // TODO: handle EINTR - char buffer[32000] = {0,}; - while(read(mIpc[READ_FROM_CHILD], buffer, sizeof(buffer)) != 0) - { - printf("%s", buffer); - fflush(stdout); - memset(buffer, 0, sizeof(buffer)); - } - // Parent is waiting for children to exit. - android::waitForChildrenOrExit(mNproc); - return true; -} - -void TestCase::setIter(size_t iter) -{ - mIter = iter; -} - -void TestCase::createTimers() -{ - char total_time[80]; - - snprintf(total_time, sizeof(total_time), "%s_total", mName); - mTestTimer = new StopWatch(total_time, 1); - mTestTimer->setDataSize(dataSize()); - - mOpenTimer = new StopWatch("open", iter() * kReadWriteFactor); - - mReadTimer = new StopWatch("read", iter() * dataSize() / chunkSize() * kReadWriteFactor); - mReadTimer->setDataSize(dataSize()); - - mWriteTimer = new StopWatch("write", iter() * dataSize() / chunkSize()); - mWriteTimer->setDataSize(dataSize()); - - mSyncTimer = new StopWatch("sync", iter()); - - mTruncateTimer = new StopWatch("truncate", iter()); - - mTraverseTimer = new StopWatch("traversal", iter()); -} - -bool TestCase::setTypeFromName(const char *test_name) -{ - strcpy(mName, test_name); - if (strcmp(mName, "write") == 0) mType = WRITE; - if (strcmp(mName, "read") == 0) mType = READ; - if (strcmp(mName, "read_write") == 0) mType = READ_WRITE; - if (strcmp(mName, "open_create") == 0) mType = OPEN_CREATE; - if (strcmp(mName, "traverse") == 0) mType = TRAVERSE; - - return UNKNOWN_TEST != mType; -} - -void TestCase::setSync(Sync s) -{ - mSync = s; -} - -const char *TestCase::syncAsStr() const -{ - return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync"); -} - -void TestCase::setFadvise(const char *advice) -{ - mFadvice = POSIX_FADV_NORMAL; - if (strcmp(advice, "sequential") == 0) - { - mFadvice = POSIX_FADV_SEQUENTIAL; - } - else if (strcmp(advice, "random") == 0) - { - mFadvice = POSIX_FADV_RANDOM; - } - else if (strcmp(advice, "noreuse") == 0) - { - mFadvice = POSIX_FADV_NOREUSE; - } - else if (strcmp(advice, "willneed") == 0) - { - mFadvice = POSIX_FADV_WILLNEED; - } - else if (strcmp(advice, "dontneed") == 0) - { - mFadvice = POSIX_FADV_DONTNEED; - } -} - -const char *TestCase::fadviseAsStr() const -{ - switch (mFadvice) { - case POSIX_FADV_NORMAL: return "fadv_normal"; - case POSIX_FADV_SEQUENTIAL: return "fadv_sequential"; - case POSIX_FADV_RANDOM: return "fadv_random"; - case POSIX_FADV_NOREUSE: return "fadv_noreuse"; - case POSIX_FADV_WILLNEED: return "fadv_willneed"; - case POSIX_FADV_DONTNEED: return "fadv_dontneed"; - default: return "fadvice_unknown"; - } -} - - -} // namespace android_test diff --git a/tests/sdcard/testcase.h b/tests/sdcard/testcase.h deleted file mode 100644 index e973d9a7..00000000 --- a/tests/sdcard/testcase.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -#ifndef SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ -#define SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ - -#include <stdlib.h> -#include "stopwatch.h" -#include "sysutil.h" - -namespace android_test { - -// Class to group test parameters and implementation. -// Takes care of forking child processes and wait for them. - -class TestCase { - public: - enum Type {UNKNOWN_TEST, WRITE, READ, OPEN_CREATE, READ_WRITE, TRAVERSE}; - enum Pipe {READ_FROM_CHILD = 0, WRITE_TO_PARENT, READ_FROM_PARENT, WRITE_TO_CHILD}; - enum Sync {NO_SYNC, FSYNC, SYNC}; - - // Reads takes less time than writes. This is a basic - // approximation of how much longer the read tasks must run to - // terminate roughly at the same time as the write tasks. - const static int kReadWriteFactor = 5; - - TestCase(const char *appName); - - ~TestCase(); - - size_t iter() const { return mIter; } - void setIter(size_t iter); - - size_t nproc() const { return mNproc; } - void setNproc(size_t val) { mNproc = val; } - - size_t dataSize() const { return mDataSize; } - void setDataSize(size_t val) { mDataSize = val; } - - size_t chunkSize() const { return mChunkSize; } - void setChunkSize(size_t val) { mChunkSize = val; } - - size_t treeDepth() const { return mTreeDepth; } - void setTreeDepth(size_t val) { mTreeDepth = val; } - - bool newFairSleepers() const { return mNewFairSleepers; } - void setNewFairSleepers(bool val) { - mNewFairSleepers = val; - android::setNewFairSleepers(val); - } - - bool normalizedSleepers() const { return mNormalizedSleepers; } - void setNormalizedSleepers(bool val) { - mNormalizedSleepers = val; - android::setNormalizedSleepers(val); - } - - Sync sync() const { return mSync; } - void setSync(Sync s); - const char *syncAsStr() const; - - bool cpuScaling() const { return mCpuScaling; } - void setCpuScaling() { mCpuScaling = true; } - - bool truncateToSize() const { return mTruncateToSize; } - void setTruncateToSize() { mTruncateToSize = true; } - - int fadvise() { return mFadvice; } - void setFadvise(const char *advice); - const char *fadviseAsStr() const; - - // Print the samples. - void setDump() { StopWatch::setPrintRawMode(true); } - - StopWatch *testTimer() { return mTestTimer; } - StopWatch *openTimer() { return mOpenTimer; } - StopWatch *readTimer() { return mReadTimer; } - StopWatch *writeTimer() { return mWriteTimer; } - StopWatch *syncTimer() { return mSyncTimer; } - StopWatch *truncateTimer() { return mTruncateTimer; } - StopWatch *traverseTimer() { return mTraverseTimer; } - - // Fork the children, run the test and wait for them to complete. - bool runTest(); - - void signalParentAndWait() { - if (!android::writePidAndWaitForReply(mIpc[WRITE_TO_PARENT], mIpc[READ_FROM_PARENT])) { - exit(1); - } - } - - void createTimers(); - bool setTypeFromName(const char *test_name); - Type type() const { return mType; } - pid_t pid() const { return mPid; } - const char *name() const { return mName; } - - // This is set to the function that will actually do the test when - // the command line arguments have been parsed. The function will - // be run in one or more child(ren) process(es). - bool (*mTestBody)(TestCase *); -private: - const char *mAppName; - size_t mDataSize; - size_t mChunkSize; - size_t mTreeDepth; - size_t mIter; - size_t mNproc; - pid_t mPid; - char mName[80]; - Type mType; - - bool mDump; // print the raw values instead of a human friendly report. - bool mCpuScaling; // true, do not turn off cpu scaling. - Sync mSync; - int mFadvice; - // When new files are created, truncate them to the final size. - bool mTruncateToSize; - - bool mNewFairSleepers; - bool mNormalizedSleepers; - - // IPC - // Parent Child(ren) - // --------------------------------------- - // 0: read from child closed - // 1: closed write to parent - // 2: closed read from parent - // 3: write to child closed - int mIpc[4]; - - StopWatch *mTestTimer; // Used to time the test overall. - StopWatch *mOpenTimer; // Used to time the open calls. - StopWatch *mReadTimer; // Used to time the read calls. - StopWatch *mWriteTimer; // Used to time the write calls. - StopWatch *mSyncTimer; // Used to time the sync/fsync calls. - StopWatch *mTruncateTimer; // Used to time the ftruncate calls. - StopWatch *mTraverseTimer; // Used to time each traversal. -}; - -} // namespace android_test - -#endif // SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ |