Merge master@5406228 into git_qt-dev-plus-aosp.
am: fcebb73df9
Change-Id: I407757aa7705628164700aca9266057430b422e6
diff --git a/include/tuningfork/tuningfork.h b/include/tuningfork/tuningfork.h
index 4b26fa1..24ff52f 100644
--- a/include/tuningfork/tuningfork.h
+++ b/include/tuningfork/tuningfork.h
@@ -19,6 +19,10 @@
#include <stdint.h>
#include <jni.h>
+#define TUNINGFORK_MAJOR_VERSION 0
+#define TUNINGFORK_MINOR_VERSION 1
+#define TUNINGFORK_PACKED_VERSION ((TUNINGFORK_MAJOR_VERSION<<16)|(TUNINGFORK_MINOR_VERSION))
+
// These are reserved instrumentation keys
enum {
TFTICK_SYSCPU = 0,
diff --git a/samples/bouncyball/build.gradle b/samples/bouncyball/build.gradle
index cf1d23d..4699ea7 100644
--- a/samples/bouncyball/build.gradle
+++ b/samples/bouncyball/build.gradle
@@ -6,7 +6,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.0-beta05'
+ classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
diff --git a/samples/cube/build.gradle b/samples/cube/build.gradle
index cf1d23d..4699ea7 100644
--- a/samples/cube/build.gradle
+++ b/samples/cube/build.gradle
@@ -6,7 +6,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.0-beta05'
+ classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
diff --git a/samples/tuningfork/tftestapp/app/src/main/cpp/Renderer.cpp b/samples/tuningfork/tftestapp/app/src/main/cpp/Renderer.cpp
index e1c0197..ddf8dac 100644
--- a/samples/tuningfork/tftestapp/app/src/main/cpp/Renderer.cpp
+++ b/samples/tuningfork/tftestapp/app/src/main/cpp/Renderer.cpp
@@ -32,9 +32,12 @@
#include "swappy/swappy.h"
#include "swappy/swappy_extra.h"
+#include "tuningfork/tuningfork.h"
#include "Scene.h"
+extern bool swappy_enabled;
+
using namespace std::chrono_literals;
namespace samples {
@@ -48,7 +51,7 @@
enqueue([=](State* state) {
state->clearSurface();
- ALOGE("Creating window surface %dx%d", width, height);
+ ALOGI("Creating window surface %dx%d", width, height);
if (!window) return;
@@ -227,7 +230,8 @@
return;
}
- Swappy_recordFrameStart(state->display, state->surface);
+ if (swappy_enabled)
+ Swappy_recordFrameStart(state->display, state->surface);
calculateFps();
@@ -252,7 +256,12 @@
state->scene.draw(aspectRatio, mTesselation);
- Swappy_swap(state->display, state->surface);
+ if (swappy_enabled)
+ Swappy_swap(state->display, state->surface);
+ else {
+ TuningFork_frameTick(TFTICK_SYSCPU);
+ eglSwapBuffers(state->display, state->surface);
+ }
// If we're still started, request another frame
requestDraw();
diff --git a/samples/tuningfork/tftestapp/app/src/main/cpp/tftestapp.cpp b/samples/tuningfork/tftestapp/app/src/main/cpp/tftestapp.cpp
index e160f12..7ec2737 100644
--- a/samples/tuningfork/tftestapp/app/src/main/cpp/tftestapp.cpp
+++ b/samples/tuningfork/tftestapp/app/src/main/cpp/tftestapp.cpp
@@ -36,6 +36,8 @@
namespace tf = tuningfork;
using namespace samples;
+bool swappy_enabled = false;
+
namespace {
constexpr TFInstrumentKey TFTICK_CHOREOGRAPHER = 4;
@@ -116,6 +118,9 @@
if (evt.has_apk_version_code()) {
eventStr << " apk_version_code : " << evt.apk_version_code() << "\n";
}
+ if (evt.has_tuningfork_version()) {
+ eventStr << " tuningfork_version : " << evt.tuningfork_version() << "\n";
+ }
eventStr << "}";
return eventStr.str();
}
@@ -181,7 +186,8 @@
JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_initTuningFork(JNIEnv *env, jobject activity) {
Swappy_init(env, activity);
- if (Swappy_isEnabled()) {
+ swappy_enabled = Swappy_isEnabled();
+ if (swappy_enabled) {
int defaultFPIndex = 3; // i.e. dev_tuningfork_fidelityparams_3.bin
int initialTimeoutMs = 1000;
int ultimateTimeoutMs = 100000;
@@ -196,7 +202,29 @@
ALOGW("Error initializing TuningFork: %d", c);
}
} else {
- ALOGW("Couldn't enable Swappy. Tuning Fork is not enabled either");
+ ALOGW("Couldn't enable Swappy.");
+ CProtobufSerialization settings = {};
+ TuningFork_findSettingsInAPK(env, activity, &settings);
+ TuningFork_init(&settings, env, activity);
+ tuningfork::CProtobufSerialization_Free(&settings);
+ int fp_count;
+ TuningFork_findFidelityParamsInAPK(env, activity, NULL, &fp_count);
+ CProtobufSerialization fps = {};
+ std::vector<CProtobufSerialization> defaultFPs(fp_count);
+ TuningFork_findFidelityParamsInAPK(env, activity, defaultFPs.data(), &fp_count);
+ CProtobufSerialization* defaultFP = &defaultFPs[fp_count/2-1]; // Middle settings level
+ if (TuningFork_getFidelityParameters(defaultFP, &fps, 1000)) {
+ SetFidelityParams(&fps);
+ tuningfork::CProtobufSerialization_Free(&fps);
+ }
+ else {
+ SetFidelityParams(defaultFP);
+ }
+ for(auto& a: defaultFPs) {
+ tuningfork::CProtobufSerialization_Free(&a);
+ }
+ TuningFork_setUploadCallback(UploadCallback);
+ SetAnnotations();
}
}
diff --git a/samples/tuningfork/tftestapp/build.gradle b/samples/tuningfork/tftestapp/build.gradle
index b9017fb..798ee14 100644
--- a/samples/tuningfork/tftestapp/build.gradle
+++ b/samples/tuningfork/tftestapp/build.gradle
@@ -7,7 +7,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.0-beta05'
+ classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/src/swappy/Swappy.cpp b/src/swappy/Swappy.cpp
index fa4ea2b..d4a32d3 100644
--- a/src/swappy/Swappy.cpp
+++ b/src/swappy/Swappy.cpp
@@ -78,6 +78,12 @@
displayClass,
"getAppVsyncOffsetNanos", "()J");
+ // getAppVsyncOffsetNanos was only added in API 21.
+ // Return gracefully if this device doesn't support it.
+ if (getAppVsyncOffsetNanos == 0 || env->ExceptionOccurred()) {
+ env->ExceptionClear();
+ return;
+ }
const long appVsyncOffsetNanos = env->CallLongMethod(display, getAppVsyncOffsetNanos);
jmethodID getPresentationDeadlineNanos = env->GetMethodID(
diff --git a/src/swappyVk/SwappyVk.cpp b/src/swappyVk/SwappyVk.cpp
index cc6877d..9c0a5a3 100644
--- a/src/swappyVk/SwappyVk.cpp
+++ b/src/swappyVk/SwappyVk.cpp
@@ -199,12 +199,14 @@
PFN_AChoreographer_postFrameCallbackDelayed mAChoreographer_postFrameCallbackDelayed = nullptr;
long mFrameID = 0;
- long mLastframeTimeNanos = 0;
+ long mTargetFrameID = 0;
+ uint64_t mLastframeTimeNanos = 0;
long mSumRefreshTime = 0;
long mSamples = 0;
+ long mCallbacksBeforeIdle = 0;
- static constexpr int CHOREOGRAPHER_THRESH = 1000;
static constexpr int MAX_SAMPLES = 5;
+ static constexpr int MAX_CALLBACKS_BEFORE_IDLE = 10;
void initGoogExtention()
{
@@ -222,7 +224,8 @@
void *looperThread();
static void frameCallback(long frameTimeNanos, void *data);
void onDisplayRefresh(long frameTimeNanos);
- void calcRefreshRate(long frameTimeNanos);
+ void calcRefreshRate(uint64_t currentTime);
+ void postChoreographerCallback();
};
void SwappyVkBase::startChoreographerThread() {
@@ -279,24 +282,37 @@
void SwappyVkBase::onDisplayRefresh(long frameTimeNanos) {
std::lock_guard<std::mutex> lock(mWaitingMutex);
- calcRefreshRate(frameTimeNanos);
- mLastframeTimeNanos = frameTimeNanos;
+ struct timespec currTime;
+ clock_gettime(CLOCK_MONOTONIC, &currTime);
+ uint64_t currentTime =
+ ((uint64_t) currTime.tv_sec * kBillion) + (uint64_t) currTime.tv_nsec;
+
+ calcRefreshRate(currentTime);
+ mLastframeTimeNanos = currentTime;
mFrameID++;
mWaitingCondition.notify_all();
+
+ // queue the next frame callback
+ if (mCallbacksBeforeIdle > 0) {
+ mCallbacksBeforeIdle--;
+ mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ }
}
-void SwappyVkBase::calcRefreshRate(long frameTimeNanos) {
- long refresh_nano = std::abs(frameTimeNanos - mLastframeTimeNanos);
+void SwappyVkBase::postChoreographerCallback() {
+ if (mCallbacksBeforeIdle == 0) {
+ mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ }
+ mCallbacksBeforeIdle = MAX_CALLBACKS_BEFORE_IDLE;
+}
+
+void SwappyVkBase::calcRefreshRate(uint64_t currentTime) {
+ long refresh_nano = currentTime - mLastframeTimeNanos;
if (mRefreshDur != 0 || mLastframeTimeNanos == 0) {
return;
}
- // ignore wrap around
- if (mLastframeTimeNanos > frameTimeNanos) {
- return;
- }
-
mSumRefreshTime += refresh_nano;
mSamples++;
@@ -662,7 +678,10 @@
mPendingSync[queue].pop_front();
mWaitingCondition.wait(lock, [&]() {
if (vkWaitForFences(mDevice, 1, &sync.fence, VK_TRUE, 0) == VK_TIMEOUT) {
- mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ postChoreographerCallback();
+
+ // adjust the target frame here as we are waiting additional frame for the fence
+ mTargetFrameID++;
return false;
}
return true;
@@ -681,19 +700,11 @@
return ret;
}
- struct timespec currTime;
- clock_gettime(CLOCK_MONOTONIC, &currTime);
- uint64_t currentTime =
- ((uint64_t) currTime.tv_sec * kBillion) + (uint64_t) currTime.tv_nsec;
-
- // do we have something in the queue ?
- if (mNextDesiredPresentTime > currentTime) {
+ {
std::unique_lock<std::mutex> lock(mWaitingMutex);
- long target = mFrameID + mInterval;
mWaitingCondition.wait(lock, [&]() {
- if (mFrameID < target) {
- // wait for the next frame as this frame is too soon
- mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ if (mFrameID < mTargetFrameID) {
+ postChoreographerCallback();
return false;
}
return true;
@@ -704,10 +715,12 @@
waitForFenceChoreographer(queue);
}
- clock_gettime(CLOCK_MONOTONIC, &currTime);
- currentTime =
- ((uint64_t) currTime.tv_sec * kBillion) + (uint64_t) currTime.tv_nsec;
- mNextDesiredPresentTime = currentTime + mRefreshDur * mInterval;
+ // Adjust the presentation time based on the current frameID we are at.
+ if(mFrameID < mTargetFrameID) {
+ ALOGE("Bad frame ID %ld < target %ld", mFrameID, mTargetFrameID);
+ mTargetFrameID = mFrameID;
+ }
+ mNextDesiredPresentTime += (mFrameID - mTargetFrameID) * mRefreshDur;
// Setup the new structures to pass:
VkPresentTimeGOOGLE pPresentTimes[pPresentInfo->swapchainCount];
@@ -750,6 +763,11 @@
pPresentInfo->pImageIndices, pPresentInfo->pResults};
ret = mpfnQueuePresentKHR(queue, &replacementPresentInfo);
+ // next present time is going to be 2 intervals from now, leaving 1 interval for cpu work
+ // and 1 interval for gpu work
+ mNextDesiredPresentTime = mLastframeTimeNanos + 2 * mRefreshDur * mInterval;
+ mTargetFrameID = mFrameID + mInterval;
+
return ret;
}
@@ -785,7 +803,7 @@
std::unique_lock<std::mutex> lock(mWaitingMutex);
mWaitingCondition.wait(lock, [&]() {
if (mRefreshDur == 0) {
- mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ postChoreographerCallback();
return false;
}
return true;
@@ -804,19 +822,17 @@
const VkPresentInfoKHR* pPresentInfo) override
{
{
- const long target = mFrameID + mInterval;
std::unique_lock<std::mutex> lock(mWaitingMutex);
-
mWaitingCondition.wait(lock, [&]() {
- if (mFrameID < target) {
- // wait for the next frame as this frame is too soon
- mAChoreographer_postFrameCallbackDelayed(mChoreographer, frameCallback, this, 1);
+ if (mFrameID < mTargetFrameID) {
+ postChoreographerCallback();
return false;
}
return true;
});
}
+ mTargetFrameID = mFrameID + mInterval;
return mpfnQueuePresentKHR(queue, pPresentInfo);
}
};
diff --git a/src/tuningfork/clearcutserializer.cpp b/src/tuningfork/clearcutserializer.cpp
index 481e042..fc11b30 100644
--- a/src/tuningfork/clearcutserializer.cpp
+++ b/src/tuningfork/clearcutserializer.cpp
@@ -45,11 +45,8 @@
std::vector<uint64_t>* v = static_cast<std::vector<uint64_t>*>(*arg);
// Encode each item
for (int i = 0; i < v->size(); ++i) {
- if(!pb_encode_tag(stream, PB_WT_STRING,
- logs_proto_tuningfork_DeviceInfo_cpu_max_freq_hz_tag))
- return false;
- if(!pb_encode_varint(stream, (*v)[i]))
- return false;
+ pb_encode_tag_for_field(stream, field);
+ pb_encode_varint(stream, (*v)[i]);
}
return true;
}
@@ -136,6 +133,8 @@
evt.apk_package_name.arg = (void*)&info.apk_package_name;
evt.has_apk_version_code = true;
evt.apk_version_code = info.apk_version_code;
+ evt.has_tuningfork_version = true;
+ evt.tuningfork_version = info.tuningfork_version;
}
void ClearcutSerializer::FillHistograms(const ProngCache& pc, TuningForkLogEvent &evt) {
diff --git a/src/tuningfork/proto/tuningfork_clearcut_log.proto b/src/tuningfork/proto/tuningfork_clearcut_log.proto
index 648bdd5..813914c 100644
--- a/src/tuningfork/proto/tuningfork_clearcut_log.proto
+++ b/src/tuningfork/proto/tuningfork_clearcut_log.proto
@@ -48,6 +48,9 @@
// Version code from APK manifest.
optional int32 apk_version_code = 7;
+
+ // Tuning fork version (upper 16 bits: major, lower 16 bits minor)
+ optional int32 tuningfork_version = 8;
}
message TuningForkHistogram {
diff --git a/src/tuningfork/tools/validation/build.gradle b/src/tuningfork/tools/validation/build.gradle
new file mode 100644
index 0000000..21b69de
--- /dev/null
+++ b/src/tuningfork/tools/validation/build.gradle
@@ -0,0 +1,66 @@
+apply plugin: 'java'
+apply plugin: 'com.google.protobuf'
+
+repositories {
+ mavenCentral()
+ google()
+ jcenter()
+}
+
+sourceSets {
+ main {
+ proto {
+ include '../../proto/tuningfork.proto'
+ }
+ }
+ test {
+ java {
+ exclude '**'
+ }
+ }
+}
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
+ }
+}
+
+dependencies {
+ compile 'com.google.guava:guava:26.0-jre'
+ compile 'com.google.protobuf:protobuf-java:3.5.1'
+ compile 'com.google.flogger:flogger:0.3.1'
+ compile 'com.google.flogger:flogger-system-backend:0.3.1'
+ compile 'com.beust:jcommander:1.7'
+
+ testCompile 'junit:junit:4.12'
+ testCompile 'com.google.truth:truth:0.43'
+ testCompile 'org.junit.jupiter:junit-jupiter:5.4.1'
+
+ protobuf files('../../proto/tuningfork.proto')
+}
+
+protobuf {
+ protoc {
+ //Download from repo
+ artifact = 'com.google.protobuf:protoc:3.0.0'
+ }
+}
+
+task createJar(type: Jar) {
+ manifest {
+ attributes 'Implementation-Title': 'Gradle Jar',
+ 'Implementation-Version': 1.0,
+ 'Main-Class': 'com.google.tuningfork.validation.TuningforkApkValidationTool'
+ }
+ baseName = 'TuningforkApkValidationTool'
+ from {
+ configurations.compile.collect {
+ it.isDirectory()? it:zipTree(it)
+ }
+ }
+ with jar
+}
\ No newline at end of file
diff --git a/src/tuningfork/tools/validation/gradlew b/src/tuningfork/tools/validation/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/src/tuningfork/tools/validation/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/src/tuningfork/tools/validation/gradlew.bat b/src/tuningfork/tools/validation/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/src/tuningfork/tools/validation/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ApkConfig.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ApkConfig.java
index fd35f3b..347fa76 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ApkConfig.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ApkConfig.java
@@ -25,6 +25,8 @@
public static final String ASSETS_DIRECTORY = "assets/tuningfork/";
public static final String DEV_TUNINGFORK_PROTO = ASSETS_DIRECTORY + "dev_tuningfork.proto";
+ public static final String DEV_TUNINGFORK_PROTO_DESCRIPTOR =
+ ASSETS_DIRECTORY + "dev_tuningfork.descriptor";
public static final String TUNINGFORK_SETTINGS = ASSETS_DIRECTORY + "tuningfork_settings.bin";
public static final Pattern DEV_FIDELITY_PATTERN =
Pattern.compile(ASSETS_DIRECTORY + "dev_tuningfork_fidelityparams_.{1,15}.bin");
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/DeveloperTuningforkParser.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/DeveloperTuningforkParser.java
index dab5889..d1c447e 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/DeveloperTuningforkParser.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/DeveloperTuningforkParser.java
@@ -19,10 +19,8 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.ListMultimap;
import com.google.common.flogger.FluentLogger;
-import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
import com.google.protobuf.ByteString;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
@@ -30,45 +28,44 @@
import java.io.File;
import java.io.IOException;
import java.util.Optional;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import java.util.regex.Pattern;
-/** Tuningfork validation tool.
- * Parses proto and settings files and validates them. */
+/** Tuningfork validation tool. Parses proto and settings files and validates them. */
public class DeveloperTuningforkParser {
- private Optional<String> devTuningfork = Optional.empty();
- private Optional<ByteString> tuningforkSettings = Optional.empty();
- private final ListMultimap<String, ByteString> devFidelityParams = LinkedListMultimap.create();
+ private Optional<File> devTuningforkProto = Optional.empty();
+ private Optional<String> tuningforkSettings = Optional.empty();
+ private ImmutableList<File> devFidelityFiles;
private final ErrorCollector errors;
- private final File protocBinary;
+ private final ExternalProtoCompiler compiler;
+ private final File folder;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- public DeveloperTuningforkParser(ErrorCollector errors, File protocBinary) {
+ public DeveloperTuningforkParser(ErrorCollector errors, File folder, File protocBinary) {
this.errors = errors;
- this.protocBinary = protocBinary;
+ this.folder = folder;
+ this.compiler = new ExternalProtoCompiler(protocBinary);
}
- public void parseJarEntry(JarFile apk, JarEntry file) throws IOException {
- if (file.getName().equals(ApkConfig.DEV_TUNINGFORK_PROTO)) {
- String content = new String(ByteStreams.toByteArray(apk.getInputStream(file)), UTF_8);
- devTuningfork = Optional.of(content);
- } else if (file.getName().equals(ApkConfig.TUNINGFORK_SETTINGS)) {
- ByteString content = ByteString.readFrom(apk.getInputStream(file));
- tuningforkSettings = Optional.of(content);
- } else if (ApkConfig.DEV_FIDELITY_PATTERN.matcher(file.getName()).find()) {
- ByteString content = ByteString.readFrom(apk.getInputStream(file));
- devFidelityParams.put(file.getName(), content);
- }
+ public void parseFilesInFolder() throws IOException {
+ devTuningforkProto = findDevTuningforkProto(folder);
+ tuningforkSettings = findTuningforkSettings(folder);
+ devFidelityFiles = findDevFidelityParams(folder);
}
- /** Validate protos and settings.*/
public void validate() throws IOException, CompilationException {
+ if (devTuningforkProto.isPresent()) {
+ logger.atInfo().log("File %s exists: OK", FolderConfig.DEV_TUNINGFORK_PROTO);
+ } else {
+ logger.atSevere().log("File %s exists: FAIL", FolderConfig.DEV_TUNINGFORK_PROTO);
+ }
+
+ File descriptorFile = new File(folder, FolderConfig.DEV_TUNINGFORK_DESCRIPTOR);
FileDescriptor devTuningforkFileDesc =
- ProtoHelper.compileContent(devTuningfork.get(), protocBinary);
+ compiler.compile(devTuningforkProto.get(), Optional.of(descriptorFile));
Descriptor annotationField = devTuningforkFileDesc.findMessageTypeByName("Annotation");
Descriptor fidelityField = devTuningforkFileDesc.findMessageTypeByName("FidelityParams");
@@ -79,16 +76,118 @@
logger.atInfo().log("Loaded Annotation message:\n" + annotationField.toProto());
logger.atInfo().log("Loaded FidelityParams message:\n" + fidelityField.toProto());
- // Validate settings only if annotations are valid
- if (!errors.hasAnnotationErrors()) {
- ValidationUtil.validateSettings(enumSizes, tuningforkSettings.get(), errors);
- Settings settings = Settings.parseFrom(tuningforkSettings.get());
- logger.atInfo().log("Loaded settings:\n" + settings);
+ validateAndSaveBinarySettings(enumSizes);
+ encodeBinaryAndValidateDevFidelity(fidelityField);
+ }
+
+ private void validateAndSaveBinarySettings(ImmutableList<Integer> enumSizes) {
+ if (tuningforkSettings.isPresent()) {
+ logger.atInfo().log("File %s exists: OK", FolderConfig.TUNINGFORK_SETTINGS_TEXTPROTO);
+ } else {
+ logger.atSevere().log("File %s exists: FAIL", FolderConfig.TUNINGFORK_SETTINGS_TEXTPROTO);
}
- // Validate devFidelityOnly only if fidelity parameters are valid
- if (!errors.hasFidelityParamsErrors()) {
- ValidationUtil.validateDevFidelityParams(devFidelityParams.values(), fidelityField, errors);
+ if (errors.hasAnnotationErrors()) {
+ logger.atSevere().log(
+ "Skip %s file check as Annotation is not valid",
+ FolderConfig.TUNINGFORK_SETTINGS_TEXTPROTO);
}
+
+ Optional<Settings> settings =
+ ValidationUtil.validateSettings(enumSizes, tuningforkSettings.get(), errors);
+
+ if (errors.hasSettingsErrors() || !settings.isPresent()) {
+ logger.atSevere().log(
+ "Skip saving %s file as %s contains errors",
+ FolderConfig.TUNINGFORK_SETTINGS_BINARY, FolderConfig.TUNINGFORK_SETTINGS_TEXTPROTO);
+ }
+
+ logger.atInfo().log("Loaded settings:\n" + settings.get());
+
+ saveBinarySettings(settings.get());
+ }
+
+ private void saveBinarySettings(Settings settings) {
+ File outFile = new File(folder, FolderConfig.TUNINGFORK_SETTINGS_BINARY);
+ try {
+ Files.write(settings.toByteArray(), outFile);
+ } catch (IOException e) {
+ logger.atSevere().withCause(e).log(
+ "Error writing settings to %s file", FolderConfig.TUNINGFORK_SETTINGS_BINARY);
+ }
+ }
+
+ private void encodeBinaryAndValidateDevFidelity(Descriptor fidelityField) {
+ if (!devFidelityFiles.isEmpty()) {
+ logger.atInfo().log(
+ "%d %s files found: OK\n %s",
+ devFidelityFiles.size(),
+ FolderConfig.DEV_FIDELITY_TEXTPROTO,
+ devFidelityFiles.toString());
+ } else {
+ logger.atSevere().log("%s files found: FAIL", FolderConfig.DEV_FIDELITY_TEXTPROTO);
+ }
+
+ if (errors.hasFidelityParamsErrors()) {
+ logger.atSevere().log(
+ "Skip %s files check as FidelityParams message is not valid",
+ FolderConfig.DEV_FIDELITY_TEXTPROTO);
+ }
+
+ devFidelityFiles.forEach(
+ textprotoFile -> encodeBinaryAndValidateDevFidelity(fidelityField, textprotoFile));
+ }
+
+ private void encodeBinaryAndValidateDevFidelity(Descriptor fidelityField, File textprotoFile) {
+ File binaryFile;
+ try {
+ binaryFile =
+ compiler.encodeFromTextprotoFile(
+ fidelityField.getFullName(),
+ devTuningforkProto.get(),
+ textprotoFile,
+ getBinaryPathForTextprotoPath(textprotoFile),
+ Optional.empty());
+ } catch (IOException | CompilationException e) {
+ errors.addError(
+ ErrorType.DEV_FIDELITY_PARAMETERS_ENCODING,
+ String.format("Encoding %s file", textprotoFile.getName()),
+ e);
+ return;
+ }
+ ByteString content;
+ try {
+ content = ByteString.copyFrom(Files.toByteArray(binaryFile));
+ } catch (IOException e) {
+ errors.addError(
+ ErrorType.DEV_FIDELITY_PARAMETERS_READING,
+ String.format("Reading %s file", binaryFile.getName()),
+ e);
+ return;
+ }
+ ValidationUtil.validateDevFidelityParams(content, fidelityField, errors);
+ }
+
+ private static String getBinaryPathForTextprotoPath(File textprotoFile) {
+ return textprotoFile.getParentFile().getAbsolutePath()
+ + "/"
+ + textprotoFile.getName().replace(".txt", ".bin");
+ }
+
+ private static Optional<File> findDevTuningforkProto(File folder) throws IOException {
+ File file = new File(folder, FolderConfig.DEV_TUNINGFORK_PROTO);
+ return Optional.of(file);
+ }
+
+ private static Optional<String> findTuningforkSettings(File folder) throws IOException {
+ File file = new File(folder, FolderConfig.TUNINGFORK_SETTINGS_TEXTPROTO);
+ String content = Files.asCharSource(file, UTF_8).read();
+ return Optional.of(content);
+ }
+
+ private static ImmutableList<File> findDevFidelityParams(File folder) throws IOException {
+ Pattern devFidelityPattern = Pattern.compile(FolderConfig.DEV_FIDELITY_TEXTPROTO);
+ return ImmutableList.copyOf(
+ folder.listFiles((dir, filename) -> devFidelityPattern.matcher(filename).find()));
}
}
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorCollector.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorCollector.java
index 95cafb8..05f1a44 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorCollector.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorCollector.java
@@ -30,9 +30,13 @@
void printStatus();
+ Boolean hasErrors(ErrorType.ErrorGroup group);
+
Boolean hasAnnotationErrors();
Boolean hasFidelityParamsErrors();
+ Boolean hasSettingsErrors();
+
Multimap<ErrorType, String> getErrors();
};
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorType.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorType.java
index ca7f8ec..c72dd27 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorType.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ErrorType.java
@@ -18,23 +18,52 @@
/** Validation errors */
public enum ErrorType {
- ANNOTATION_EMPTY, // Annotation field is empty
- ANNOTATION_COMPLEX, // Annotation field is too complex - contains oneofs/nestedtypes/extensions
- ANNOTATION_TYPE, // Annotation must contains enums only
+ // Annotation field is empty
+ ANNOTATION_EMPTY(ErrorGroup.ANNOTATION),
+ // Annotation field is too complex - contains oneofs/nestedtypes/extensions
+ ANNOTATION_COMPLEX(ErrorGroup.ANNOTATION),
+ // Annotation must contains enums only
+ ANNOTATION_TYPE(ErrorGroup.ANNOTATION),
+ // FidelityParams fied is empty
+ FIDELITY_PARAMS_EMPTY(ErrorGroup.FIDELITY),
+ // FidelityParams field is complex - contains oneof/nestedtypes/extensions
+ FIDELITY_PARAMS_COMPLEX(ErrorGroup.FIDELITY),
+ // FidelityParams can only contains float, int32 or enum
+ FIDELITY_PARAMS_TYPE(ErrorGroup.FIDELITY),
+ // Fidelity parameters are empty
+ DEV_FIDELITY_PARAMETERS_EMPTY(ErrorGroup.DEV_FIDELITY),
+ // Fidelity parameters parsing error
+ DEV_FIDELITY_PARAMETERS_PARSING(ErrorGroup.DEV_FIDELITY),
+ // Fidelity parameters encoding textproto file
+ DEV_FIDELITY_PARAMETERS_ENCODING(ErrorGroup.DEV_FIDELITY),
+ // Fidelity parameters reading file
+ DEV_FIDELITY_PARAMETERS_READING(ErrorGroup.DEV_FIDELITY),
+ // Parsing error
+ SETTINGS_PARSING(ErrorGroup.SETTINGS),
+ // Histogram field is empty
+ HISTOGRAM_EMPTY(ErrorGroup.SETTINGS),
+ // Aggreagtion field is empty
+ AGGREGATION_EMPTY(ErrorGroup.SETTINGS),
+ // Aggregation contains incorrect max_instrumentation_keys field
+ AGGREGATION_INSTRUMENTATION_KEY(ErrorGroup.SETTINGS),
+ // Aggregation contains incorrect annotation_enum_sizes
+ AGGREGATION_ANNOTATIONS(ErrorGroup.SETTINGS);
- FIDELITY_PARAMS_EMPTY, // FidelityParams fied is empty
- FIDELITY_PARAMS_COMPLEX, // FidelityParams field is complex - contains
- // oneof/nestedtypes/extensions
- FIDELITY_PARAMS_TYPE, // FidelityParams can only contains float, int32 or enum
+ private final ErrorGroup group;
- DEV_FIDELITY_PARAMETERS_EMPTY, // Fidelity parameters are empty
- DEV_FIDELITY_PARAMETERS_PARSING, // Fidelity parameters parsing error
+ public ErrorGroup getGroup() {
+ return group;
+ }
- SETTINGS_PARSING, // Parsing error
+ ErrorType(ErrorGroup group) {
+ this.group = group;
+ }
- HISTOGRAM_EMPTY, // Histogram field is empty
-
- AGGREGATION_EMPTY, // Aggreagtion field is empty
- AGGREGATION_INSTRUMENTATION_KEY, // Aggregation contains incorrect max_instrumentation_keys field
- AGGREGATION_ANNOTATIONS, // Aggregation contains incorrect annotation_enum_sizes
+ /** Validation group of errors */
+ public enum ErrorGroup {
+ ANNOTATION,
+ FIDELITY,
+ DEV_FIDELITY,
+ SETTINGS,
+ }
};
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ExternalProtoCompiler.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ExternalProtoCompiler.java
index b35e667..d8f8c84 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ExternalProtoCompiler.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ExternalProtoCompiler.java
@@ -1,9 +1,24 @@
-// Copyright 2009 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2019 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 com.google.tuningfork.validation;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.Descriptors.DescriptorValidationException;
@@ -12,7 +27,7 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.util.List;
+import java.util.Optional;
/** Compiles .proto file into a {@link FileDescriptor} */
public class ExternalProtoCompiler {
@@ -25,14 +40,15 @@
protoPath = protoBinary.getAbsolutePath();
}
- public FileDescriptor compile(File file) throws IOException, CompilationException {
+ public FileDescriptor compile(File file, Optional<File> outFile)
+ throws IOException, CompilationException {
Preconditions.checkNotNull(file, "file");
- FileDescriptor descriptor = buildAndRunCompilerProcess(file);
+ FileDescriptor descriptor = buildAndRunCompilerProcess(file, outFile);
return descriptor;
}
- public byte[] runCommand(List<String> commandLine) throws IOException, CompilationException {
- Process process = new ProcessBuilder(commandLine).start();
+ public byte[] runCommand(ProcessBuilder processBuilder) throws IOException, CompilationException {
+ Process process = processBuilder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
@@ -44,13 +60,16 @@
return result;
}
- private FileDescriptor buildAndRunCompilerProcess(File file)
+ private FileDescriptor buildAndRunCompilerProcess(File file, Optional<File> outFile)
throws IOException, CompilationException {
- List<String> commandLine = createCommandLine(file);
- byte[] result = runCommand(commandLine);
+ ImmutableList<String> commandLine = createCommandLine(file);
+ byte[] result = runCommand(new ProcessBuilder(commandLine));
try {
FileDescriptorSet fileSet = FileDescriptorSet.parseFrom(result);
+ if (outFile.isPresent()) {
+ Files.write(fileSet.toByteArray(), outFile.get());
+ }
for (FileDescriptorProto descProto : fileSet.getFileList()) {
if (descProto.getName().equals(file.getName())) {
return FileDescriptor.buildFrom(descProto, emptyDeps);
@@ -63,7 +82,49 @@
String.format("Descriptor for [%s] does not exist.", file.getName()));
}
- private List<String> createCommandLine(File file) {
+ /* Decode textproto message from text(textprotoFile) into binary(binFile) */
+ public File encodeFromTextprotoFile(
+ String message,
+ File protoFile,
+ File textprotoFile,
+ String binaryPath,
+ Optional<File> errorFile)
+ throws IOException, CompilationException {
+ ImmutableList<String> command = encodeCommandLine(message, protoFile);
+
+ File binFile = new File(binaryPath);
+
+ ProcessBuilder builder =
+ new ProcessBuilder(command).redirectInput(textprotoFile).redirectOutput(binFile);
+
+ if (errorFile.isPresent()) {
+ builder.redirectError(errorFile.get());
+ }
+
+ runCommand(builder);
+ return binFile;
+ }
+
+ /* Decode textproto message from binary(binFile) into text(textFile) */
+ public File decodeToTextprotoFile(
+ String message, File protoFile, String textprotoPath, File binFile, Optional<File> errorFile)
+ throws IOException, CompilationException {
+ ImmutableList<String> command = decodeCommandLine(message, protoFile);
+
+ File textprotoFile = new File(textprotoPath);
+
+ ProcessBuilder builder =
+ new ProcessBuilder(command).redirectInput(binFile).redirectOutput(textprotoFile);
+
+ if (errorFile.isPresent()) {
+ builder.redirectError(errorFile.get());
+ }
+
+ runCommand(builder);
+ return textprotoFile;
+ }
+
+ private ImmutableList<String> createCommandLine(File file) {
return ImmutableList.of(
protoPath,
"-o",
@@ -72,4 +133,22 @@
file.getName() + "=" + file.getAbsolutePath(), // That should be one line
file.getName());
}
+
+ private ImmutableList<String> encodeCommandLine(String message, File protoFile) {
+ return ImmutableList.of(
+ protoPath,
+ "--encode=" + message,
+ "-I",
+ protoFile.getName() + "=" + protoFile.getAbsolutePath(), // That should be one line
+ protoFile.getName());
+ }
+
+ private ImmutableList<String> decodeCommandLine(String message, File protoFile) {
+ return ImmutableList.of(
+ protoPath,
+ "--decode=" + message,
+ "-I",
+ protoFile.getName() + "=" + protoFile.getAbsolutePath(), // That should be one line
+ protoFile.getName());
+ }
}
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/FolderConfig.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/FolderConfig.java
new file mode 100644
index 0000000..f3c2615
--- /dev/null
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/FolderConfig.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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 com.google.tuningfork.validation;
+
+/** Settings and proto file names for assets/tuningfork folder */
+final class FolderConfig {
+
+ public static final String DEV_TUNINGFORK_PROTO = "dev_tuningfork.proto";
+ public static final String DEV_TUNINGFORK_DESCRIPTOR = "dev_tuningfork.descriptor";
+ public static final String TUNINGFORK_SETTINGS_TEXTPROTO = "tuningfork_settings.txt";
+ public static final String TUNINGFORK_SETTINGS_BINARY = "tuningfork_settings.bin";
+ public static final String DEV_FIDELITY_TEXTPROTO = "dev_tuningfork_fidelityparams_.{1,15}.txt";
+}
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ParserErrorCollector.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ParserErrorCollector.java
index 547e27f..4da322c 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ParserErrorCollector.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ParserErrorCollector.java
@@ -56,31 +56,42 @@
public void printStatus() {
StringBuilder builder = new StringBuilder();
for (ErrorType errorType : ErrorType.values()) {
- builder.append(errorType).append(" : ");
int errorCount = errors.get(errorType).size();
- if (errorCount == 0) {
- builder.append("OK");
- } else {
- builder.append(errorCount);
- builder.append(" ERRORS\n\t");
- builder.append(errors.get(errorType));
+ if (errorCount != 0) {
+ builder
+ .append(errorType)
+ .append(" : ")
+ .append(errorCount)
+ .append(" ERRORS\n\t")
+ .append(errors.get(errorType))
+ .append("\n");
}
- builder.append("\n");
}
- logger.atInfo().log(builder.toString());
+ logger.atWarning().log(builder.toString());
+ }
+
+ @Override
+ public Boolean hasErrors(ErrorType.ErrorGroup group) {
+ for (ErrorType errorType : ErrorType.values()) {
+ if (errorType.getGroup() == group && errors.containsKey(errorType)) {
+ return true;
+ }
+ }
+ return false;
}
@Override
public Boolean hasAnnotationErrors() {
- return errors.containsKey(ErrorType.ANNOTATION_EMPTY)
- || errors.containsKey(ErrorType.ANNOTATION_COMPLEX)
- || errors.containsKey(ErrorType.ANNOTATION_TYPE);
+ return hasErrors(ErrorType.ErrorGroup.ANNOTATION);
}
@Override
public Boolean hasFidelityParamsErrors() {
- return errors.containsKey(ErrorType.FIDELITY_PARAMS_EMPTY)
- || errors.containsKey(ErrorType.FIDELITY_PARAMS_COMPLEX)
- || errors.containsKey(ErrorType.FIDELITY_PARAMS_TYPE);
+ return hasErrors(ErrorType.ErrorGroup.FIDELITY);
+ }
+
+ @Override
+ public Boolean hasSettingsErrors() {
+ return hasErrors(ErrorType.ErrorGroup.SETTINGS);
}
}
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ProtoHelper.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ProtoHelper.java
deleted file mode 100644
index 855944d..0000000
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ProtoHelper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.google.tuningfork.validation;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.io.Files;
-import com.google.protobuf.Descriptors.FileDescriptor;
-import java.io.File;
-import java.io.IOException;
-
-/** Compile {@link FileDescriptor} from proto file content */
-final class ProtoHelper {
-
- private static final String TEMP_FILE_NAME = "tempfile.proto";
-
- private ProtoHelper() {}
-
- public static FileDescriptor compileContent(String content, File protocBinary)
- throws IOException, CompilationException {
- File file = File.createTempFile(TEMP_FILE_NAME, null);
- Files.asCharSink(file, UTF_8).write(content);
- ExternalProtoCompiler compiler = new ExternalProtoCompiler(protocBinary);
- FileDescriptor desc = compiler.compile(file);
- file.delete();
- return desc;
- }
-}
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/TuningforkApkValidationTool.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/TuningforkApkValidationTool.java
index 3081147..b3bf50b 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/TuningforkApkValidationTool.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/TuningforkApkValidationTool.java
@@ -18,79 +18,76 @@
import static com.google.common.base.Preconditions.checkArgument;
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
import com.google.common.base.Strings;
-import com.google.common.flags.Flag;
-import com.google.common.flags.FlagSpec;
-import com.google.common.flags.Flags;
import com.google.common.flogger.FluentLogger;
import java.io.File;
import java.io.IOException;
-import java.util.Enumeration;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
/** APK Validation tool for Tuningfork */
final class TuningforkApkValidationTool {
+
+ private static class Parameters {
+ @Parameter(
+ names = {"--tuningforkPath"},
+ description = "Path to an assets/tuningfork folder")
+ public String tuningforkPath;
+
+ @Parameter(
+ names = {"--protoCompiler"},
+ description = "Path to protoc binary")
+ public String protoCompiler;
+ }
+
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- @FlagSpec(help = "Path to apk file")
- public static final Flag<String> apkPath = Flag.nullString();
-
- @FlagSpec(help = "Path to proto compiler")
- public static final Flag<String> protoCompiler = Flag.nullString();
-
public static void main(String[] args) {
- Flags.parse(args);
+ Parameters parameters = new Parameters();
+ new JCommander(parameters, args);
checkArgument(
- !Strings.isNullOrEmpty(apkPath.get()),
- "You need to specify path to your apk file --apkPath");
+ !Strings.isNullOrEmpty(parameters.tuningforkPath),
+ "You need to specify path to your tuningfork settings folder --tuningforkPath");
checkArgument(
- !Strings.isNullOrEmpty(protoCompiler.get()),
+ !Strings.isNullOrEmpty(parameters.protoCompiler),
"You need to specify path to proto compiler --protoCompiler");
- File apkFile = new File(apkPath.get());
- if (!apkFile.exists()) {
- logger.atSevere().log("APK File does not exist %s", apkPath.get());
- return;
+ File tuningforkFolder = new File(parameters.tuningforkPath);
+ if (!tuningforkFolder.exists()) {
+ logger.atSevere().log(
+ "Tuningfork settings folder does not exist %s", parameters.tuningforkPath);
}
- File protoCompilerFile = new File(protoCompiler.get());
+ if (!tuningforkFolder.isDirectory()) {
+ logger.atSevere().log(
+ "--tuningforkPath=[%s] is not a path to a folder", parameters.tuningforkPath);
+ }
+
+ File protoCompilerFile = new File(parameters.protoCompiler);
if (!protoCompilerFile.exists()) {
- logger.atSevere().log("Proto compiler file does not exist %s", protoCompiler.get());
- return;
+ logger.atSevere().log("Proto compiler file does not exist %s", parameters.protoCompiler);
}
- logger.atInfo().log("Start validation of %s...", apkFile.getName());
-
- JarFile jarApk;
-
- try {
- jarApk = new JarFile(apkFile);
- } catch (IOException e) {
- logger.atSevere().withCause(e).log("Can not open apk file %s", apkFile.getName());
- return;
+ if (!protoCompilerFile.isFile() || !protoCompilerFile.canExecute()) {
+ logger.atSevere().log(
+ "--protoCompiler=[%s] is not a path to an executable file", parameters.protoCompiler);
}
+ logger.atInfo().log("Start validation of %s...", tuningforkFolder.getPath());
+
ErrorCollector errors = new ParserErrorCollector();
- DeveloperTuningforkParser parser = new DeveloperTuningforkParser(errors, protoCompilerFile);
-
- Enumeration<JarEntry> apkFiles = jarApk.entries();
- while (apkFiles.hasMoreElements()) {
- JarEntry file = apkFiles.nextElement();
- try {
- parser.parseJarEntry(jarApk, file);
- } catch (Exception e) {
- logger.atWarning().withCause(e).log("Can not parse apk entry %s", file.getName());
- }
- }
+ DeveloperTuningforkParser parser =
+ new DeveloperTuningforkParser(errors, tuningforkFolder, protoCompilerFile);
try {
+ parser.parseFilesInFolder();
parser.validate();
if (errors.getErrorCount() == 0) {
- logger.atInfo().log("Apk %s is valid", apkFile.getName());
+ logger.atInfo().log("Tuning Fork settings are valid");
} else {
+ logger.atWarning().log("Tuning Fork settings are invalid");
errors.printStatus();
}
} catch (IOException | CompilationException e) {
diff --git a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ValidationUtil.java b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ValidationUtil.java
index b41982f..e2f5ce9 100644
--- a/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ValidationUtil.java
+++ b/src/tuningfork/tools/validation/src/main/java/com/google/tuningfork/validation/ValidationUtil.java
@@ -22,13 +22,16 @@
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.TextFormat;
+import com.google.protobuf.TextFormat.ParseException;
import com.google.tuningfork.Tuningfork.Settings;
import com.google.tuningfork.Tuningfork.Settings.AggregationStrategy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
-/** Utility methods for validating Tuning Fork protos and settings.*/
+/** Utility methods for validating Tuning Fork protos and settings. */
final class ValidationUtil {
private ValidationUtil() {}
@@ -40,6 +43,22 @@
FieldDescriptor.Type.ENUM, FieldDescriptor.Type.FLOAT, FieldDescriptor.Type.INT32);
/* Validate settings */
+ public static Optional<Settings> validateSettings(
+ List<Integer> enumSizes, String settingsTextProto, ErrorCollector errors) {
+ try {
+ Settings.Builder builder = Settings.newBuilder();
+ TextFormat.merge(settingsTextProto, builder);
+ Settings settings = builder.build();
+ validateSettingsAggregation(settings, enumSizes, errors);
+ validateSettingsHistograms(settings, errors);
+ return Optional.of(settings);
+ } catch (ParseException e) {
+ errors.addError(ErrorType.SETTINGS_PARSING, "Parsing tuningfork_settings.txt", e);
+ return Optional.empty();
+ }
+ }
+
+ /* Validate settings */
public static final void validateSettings(
List<Integer> enumSizes, ByteString settingsContent, ErrorCollector errors) {
try {
diff --git a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/DeveloperTuningforkParserTest.java b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/DeveloperTuningforkParserTest.java
new file mode 100644
index 0000000..f57a849
--- /dev/null
+++ b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/DeveloperTuningforkParserTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 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 com.google.tuningfork.validation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.io.Files;
+import com.google.devtools.build.runtime.Runfiles;
+import com.google.protobuf.ByteString;
+import com.google.testing.testsize.MediumTest;
+import com.google.tuningfork.DevTuningfork.FidelityParams;
+import com.google.tuningfork.DevTuningfork.QualitySettings;
+import com.google.tuningfork.Tuningfork.Settings;
+import com.google.tuningfork.Tuningfork.Settings.AggregationStrategy;
+import com.google.tuningfork.Tuningfork.Settings.Histogram;
+import java.io.File;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public final class DeveloperTuningforkParserTest {
+
+ @Rule
+ // Override default behavior to allow overwriting files.
+ public TemporaryFolder tempFolder =
+ new TemporaryFolder() {
+ @Override
+ public File newFile(String filename) {
+ return new File(getRoot(), filename);
+ }
+ };
+
+ private final TestdataHelper helper = new TestdataHelper(tempFolder);
+ private final ErrorCollector errors = new ParserErrorCollector();
+
+ private DeveloperTuningforkParser parser;
+ private final Settings settings =
+ Settings.newBuilder()
+ .setAggregationStrategy(
+ AggregationStrategy.newBuilder()
+ .addAllAnnotationEnumSize(Arrays.asList(2))
+ .setMaxInstrumentationKeys(100))
+ .addHistograms(Histogram.getDefaultInstance())
+ .build();
+
+ private final FidelityParams devParameters1 =
+ FidelityParams.newBuilder()
+ .setIntField(10)
+ .setFloatField(1.5f)
+ .setQualitySettings(QualitySettings.FAST)
+ .build();
+
+ private final FidelityParams devParameters2 = FidelityParams.newBuilder().setIntField(10).build();
+ private final FidelityParams devParameters3 = FidelityParams.getDefaultInstance();
+
+ private static final File PROTOC_BINARY =
+ Runfiles.location("net/proto2/compiler/public/protocol_compiler");
+
+ @Before
+ public void setUp() throws Exception {
+ parser = new DeveloperTuningforkParser(errors, tempFolder.getRoot(), PROTOC_BINARY);
+ helper.getFile("dev_tuningfork.proto");
+ helper.createFile("tuningfork_settings.txt", settings.toString());
+ helper.createFile("dev_tuningfork_fidelityparams_1.txt", devParameters1.toString());
+ helper.createFile("dev_tuningfork_fidelityparams_2.txt", devParameters2.toString());
+ helper.createFile("dev_tuningfork_fidelityparams_3.txt", devParameters3.toString());
+ parser.parseFilesInFolder();
+ }
+
+ @Test
+ public void checkNoErrors() throws Exception {
+ parser.validate();
+ assertThat(errors.getErrorCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void checkSettings() throws Exception {
+ parser.validate();
+ File settingsFile = new File(tempFolder.getRoot(), "tuningfork_settings.bin");
+ ByteString settingsBinary = ByteString.copyFrom(Files.toByteArray(settingsFile));
+ Settings parsed = Settings.parseFrom(settingsBinary);
+
+ assertThat(parsed).isEqualTo(settings);
+ assertThat(errors.hasSettingsErrors()).isFalse();
+ }
+
+ @Test
+ public void checkFidelityParametersFiles() throws Exception {
+ parser.validate();
+ File file1 = new File(tempFolder.getRoot(), "dev_tuningfork_fidelityparams_1.bin");
+ File file2 = new File(tempFolder.getRoot(), "dev_tuningfork_fidelityparams_2.bin");
+ File file3 = new File(tempFolder.getRoot(), "dev_tuningfork_fidelityparams_3.bin");
+ File file4 = new File(tempFolder.getRoot(), "dev_tuningfork_fidelityparams_4.bin");
+
+ assertThat(file1.exists()).isTrue();
+ assertThat(file2.exists()).isTrue();
+ assertThat(file3.exists()).isTrue();
+ assertThat(file4.exists()).isFalse();
+ }
+
+ @Test
+ public void checkFidelityParameters() throws Exception {
+ parser.validate();
+ File devFidelityFile = new File(tempFolder.getRoot(), "dev_tuningfork_fidelityparams_1.bin");
+ ByteString devFidelityBinary = ByteString.copyFrom(Files.toByteArray(devFidelityFile));
+ FidelityParams parsed = FidelityParams.parseFrom(devFidelityBinary);
+
+ assertThat(parsed).isEqualTo(devParameters1);
+ assertThat(errors.hasFidelityParamsErrors()).isFalse();
+ }
+}
diff --git a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ExternalProtoCompilerTest.java b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ExternalProtoCompilerTest.java
index 72d9fc3..314cb40 100644
--- a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ExternalProtoCompilerTest.java
+++ b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ExternalProtoCompilerTest.java
@@ -1,16 +1,36 @@
+/*
+ * Copyright (C) 2019 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 com.google.tuningfork.validation;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.io.Files;
import com.google.devtools.build.runtime.Runfiles;
+import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import java.io.File;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -49,7 +69,7 @@
public void compileValid() throws Exception {
File file = helper.getFile("compile_valid.proto");
- FileDescriptor fDesc = compiler.compile(file);
+ FileDescriptor fDesc = compiler.compile(file, Optional.empty());
Descriptor messageDesc = fDesc.findMessageTypeByName("Message");
Descriptor anotherDesc = fDesc.findMessageTypeByName("AnotherMessage");
@@ -58,10 +78,30 @@
}
@Test
+ public void compareDescriptors() throws Exception {
+ File file = helper.getFile("compile_valid.proto");
+ File outFile = new File(tempFolder.getRoot(), "compile_valid.descriptor");
+
+ FileDescriptor stdoutDescriptor = compiler.compile(file, Optional.of(outFile));
+
+ Descriptor messageDesc = stdoutDescriptor.findMessageTypeByName("Message");
+ Descriptor anotherDesc = stdoutDescriptor.findMessageTypeByName("AnotherMessage");
+ FileDescriptorSet fileSet = FileDescriptorSet.parseFrom(Files.toByteArray(outFile));
+ FileDescriptor outFileDescriptor =
+ FileDescriptor.buildFrom(
+ Iterables.getOnlyElement(fileSet.getFileList()), new FileDescriptor[] {});
+
+ assertThat(messageDesc).isNotNull();
+ assertThat(anotherDesc).isNotNull();
+ assertThat(outFile).isNotNull();
+ assertThat(stdoutDescriptor.toProto()).isEqualTo(outFileDescriptor.toProto());
+ }
+
+ @Test
public void compileInvalid() throws Exception {
File file = helper.getFile("compile_invalid.proto");
CompilationException expected =
- assertThrows(CompilationException.class, () -> compiler.compile(file));
+ assertThrows(CompilationException.class, () -> compiler.compile(file, Optional.empty()));
assertThat(expected)
.hasMessageThat()
@@ -72,7 +112,7 @@
public void compileWithDeps() throws Exception {
File file = helper.getFile("compile_with_deps.proto");
CompilationException expected =
- assertThrows(CompilationException.class, () -> compiler.compile(file));
+ assertThrows(CompilationException.class, () -> compiler.compile(file, Optional.empty()));
assertThat(expected)
.hasMessageThat()
@@ -80,9 +120,55 @@
}
@Test
+ public void compileDevTuningfork() throws Exception {
+ File file = helper.getFile("dev_tuningfork.proto");
+
+ FileDescriptor fDesc = compiler.compile(file, Optional.empty());
+
+ Descriptor annotation = fDesc.findMessageTypeByName("Annotation");
+ Descriptor fidelityParams = fDesc.findMessageTypeByName("FidelityParams");
+ assertThat(annotation).isNotNull();
+ assertThat(fidelityParams).isNotNull();
+ }
+
+ @Test
+ public void encodeAndDecode() throws Exception {
+ String message = "com.google.tuningfork.FidelityParams";
+ File protoFile = helper.getFile("dev_tuningfork.proto");
+ File originalTextFile = helper.getFile("dev_tuningfork_fidelityparams_1.txt");
+ Optional<File> errorFile = Optional.of(tempFolder.newFile("errors.txt"));
+ String root = tempFolder.getRoot().getAbsolutePath();
+ File binaryFile =
+ compiler.encodeFromTextprotoFile(
+ message,
+ protoFile,
+ originalTextFile,
+ root + "/dev_tuningfork_fidelityparams_1.bin",
+ errorFile);
+
+ byte[] error = Files.toByteArray(errorFile.get());
+ assertThat(error).isEqualTo(new byte[0]);
+
+ File decodedTextFile =
+ compiler.decodeToTextprotoFile(
+ message,
+ protoFile,
+ root + "/dev_tuningfork_fidelityparams_decoded.txt",
+ binaryFile,
+ errorFile);
+
+ String originalMessage = Files.asCharSource(originalTextFile, UTF_8).read();
+ String decodedMessage = Files.asCharSource(decodedTextFile, UTF_8).read();
+ error = Files.toByteArray(errorFile.get());
+ assertThat(error).isEqualTo(new byte[0]);
+ assertThat(decodedMessage).isEqualTo(originalMessage);
+ }
+
+ @Test
public void runEchoCommand() throws Exception {
String expected = "Hello world";
- String result = new String(compiler.runCommand(Arrays.asList("echo", expected)), UTF_8);
+ ProcessBuilder builder = new ProcessBuilder(Arrays.asList("echo", expected));
+ String result = new String(compiler.runCommand(builder), UTF_8);
assertThat(result).startsWith(expected);
}
}
diff --git a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ProtoCompilerHelper.java b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ProtoCompilerHelper.java
index 2604120..d9ef5a9 100644
--- a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ProtoCompilerHelper.java
+++ b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ProtoCompilerHelper.java
@@ -22,6 +22,7 @@
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import java.io.File;
+import java.util.Optional;
import org.junit.rules.TemporaryFolder;
/** Base class for tests that need to create proto Descriptors */
@@ -39,7 +40,7 @@
public Descriptor getDescriptor(String fileName, String message, String descName)
throws Exception {
File file = testdata.getFile(fileName);
- FileDescriptor fDesc = compiler.compile(file);
+ FileDescriptor fDesc = compiler.compile(file, Optional.empty());
assertThat(fDesc).isNotNull();
Descriptor desc = fDesc.findMessageTypeByName(descName);
return desc;
diff --git a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ValidationUtilTest.java b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ValidationUtilTest.java
index 767ab48..a2d915a 100644
--- a/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ValidationUtilTest.java
+++ b/src/tuningfork/tools/validation/src/test/java/com/google/tuningfork/validation/ValidationUtilTest.java
@@ -20,12 +20,13 @@
import com.google.protobuf.ByteString;
import com.google.protobuf.Descriptors.Descriptor;
+import com.google.testing.testsize.MediumTest;
import com.google.tuningfork.Tuningfork.Settings;
import com.google.tuningfork.Tuningfork.Settings.AggregationStrategy;
import com.google.tuningfork.Tuningfork.Settings.Histogram;
-import com.google.testing.testsize.MediumTest;
import java.io.File;
import java.util.Arrays;
+import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -53,6 +54,26 @@
private final ErrorCollector errors = new ParserErrorCollector();
@Test
+ public void settingsValid() throws Exception {
+ AggregationStrategy aggregation =
+ AggregationStrategy.newBuilder()
+ .addAllAnnotationEnumSize(Arrays.asList(5, 10))
+ .setMaxInstrumentationKeys(100)
+ .build();
+ Settings settings =
+ Settings.newBuilder()
+ .setAggregationStrategy(aggregation)
+ .addHistograms(Histogram.getDefaultInstance())
+ .build();
+
+ Optional<Settings> parsedSettings =
+ ValidationUtil.validateSettings(Arrays.asList(5, 10), settings.toString(), errors);
+
+ assertThat(errors.getErrorCount()).isEqualTo(0);
+ assertThat(parsedSettings.get()).isEqualTo(settings);
+ }
+
+ @Test
public void settingsHistogramsValid() throws Exception {
Settings settings = Settings.newBuilder().addHistograms(Histogram.getDefaultInstance()).build();
diff --git a/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork.proto b/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork.proto
new file mode 100644
index 0000000..da618e2
--- /dev/null
+++ b/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork.proto
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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
+ */
+
+syntax = "proto3";
+
+package com.google.tuningfork;
+
+option java_package = "com.google.tuningfork";
+
+enum LoadingState {
+ UNKNOWN = 0;
+ NOT_LOADING = 1;
+}
+
+message Annotation {
+ LoadingState loading_state = 1;
+}
+
+enum QualitySettings {
+ UNKNOWN_QUALITY = 0;
+ FAST = 1;
+ SIMPLE = 2;
+ GOOD = 3;
+ BEAUTIFUL = 4;
+ FANTASTIC = 5;
+}
+
+message FidelityParams {
+ QualitySettings quality_settings = 1;
+ int32 int_field = 2;
+ float float_field = 3;
+}
diff --git a/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork_fidelityparams_1.txt b/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork_fidelityparams_1.txt
new file mode 100644
index 0000000..21152fc
--- /dev/null
+++ b/src/tuningfork/tools/validation/src/test/resources/testdata/dev_tuningfork_fidelityparams_1.txt
@@ -0,0 +1,2 @@
+quality_settings: FANTASTIC
+int_field: 10
diff --git a/src/tuningfork/tuningfork_internal.h b/src/tuningfork/tuningfork_internal.h
index 9ccc0ad..3282249 100644
--- a/src/tuningfork/tuningfork_internal.h
+++ b/src/tuningfork/tuningfork_internal.h
@@ -74,6 +74,7 @@
std::vector<uint64_t> cpu_max_freq_hz;
std::string apk_package_name;
int apk_version_code;
+ int tuningfork_version;
};
class Backend {
diff --git a/src/tuningfork/tuningfork_utils.cpp b/src/tuningfork/tuningfork_utils.cpp
index 7894e48..7158d65 100644
--- a/src/tuningfork/tuningfork_utils.cpp
+++ b/src/tuningfork/tuningfork_utils.cpp
@@ -139,4 +139,17 @@
} // namespace file_utils
+std::string UniqueId(JNIEnv* env) {
+ jclass uuid_class = env->FindClass("java/util/UUID");
+ jmethodID randomUUID = env->GetStaticMethodID( uuid_class, "randomUUID",
+ "()Ljava/util/UUID;");
+ jobject uuid = env->CallStaticObjectMethod(uuid_class, randomUUID);
+ jmethodID toString = env->GetMethodID( uuid_class, "toString", "()Ljava/lang/String;");
+ jstring uuid_string = (jstring)env->CallObjectMethod(uuid, toString);
+ const char *uuid_chars = env->GetStringUTFChars( uuid_string, NULL );
+ std::string temp_uuid( uuid_chars );
+ env->ReleaseStringUTFChars( uuid_string, uuid_chars );
+ return temp_uuid;
+}
+
} // namespace tuningfork
diff --git a/src/tuningfork/tuningfork_utils.h b/src/tuningfork/tuningfork_utils.h
index ef16f84..63df285 100644
--- a/src/tuningfork/tuningfork_utils.h
+++ b/src/tuningfork/tuningfork_utils.h
@@ -49,4 +49,7 @@
} // namespace file_utils
+// Get a unique identifier using java.util.UUID
+std::string UniqueId(JNIEnv* env);
+
} // namespace tuningfork
diff --git a/src/tuningfork/uploadthread.cpp b/src/tuningfork/uploadthread.cpp
index 12d0c3d..244dc7a 100644
--- a/src/tuningfork/uploadthread.cpp
+++ b/src/tuningfork/uploadthread.cpp
@@ -186,22 +186,26 @@
extra_info.build_version_sdk = getSystemPropViaGet("ro.build.version.sdk");
extra_info.build_fingerprint = getSystemPropViaGet("ro.build.fingerprint");
+ extra_info.session_id = UniqueId(env);
+
extra_info.cpu_max_freq_hz.clear();
for(int index = 1;;++index) {
std::stringstream str;
- str << "/sys/devices/system/cpu/cpu/" << index << "/cpufreq/cpuinfo_max_freq";
+ str << "/sys/devices/system/cpu/cpu" << index << "/cpufreq/cpuinfo_max_freq";
auto cpu_freq_file = slurpFile(str.str().c_str());
if (cpu_freq_file.empty())
break;
uint64_t freq;
std::istringstream cstr(cpu_freq_file);
cstr >> freq;
- // TODO check units
- extra_info.cpu_max_freq_hz.push_back(freq);
+ extra_info.cpu_max_freq_hz.push_back(freq*1000); // File is in kHz
}
extra_info.apk_version_code = apk_utils::GetVersionCode(env, activity,
&extra_info.apk_package_name);
+
+ extra_info.tuningfork_version = TUNINGFORK_PACKED_VERSION;
+
return extra_info;
}
diff --git a/third_party/cube/build.gradle b/third_party/cube/build.gradle
index 51b175b..4699ea7 100644
--- a/third_party/cube/build.gradle
+++ b/third_party/cube/build.gradle
@@ -6,7 +6,7 @@
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}