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 }