@ -18,8 +18,10 @@
# include "BenchmarkGen.h"
# include "VolumeManager.h"
# include <android-base/chrono_utils.h>
# include <android-base/file.h>
# include <android-base/logging.h>
# include <cutils/iosched_policy.h>
# include <hardware_legacy/power.h>
# include <private/android_filesystem_config.h>
@ -30,18 +32,65 @@
# include <sys/resource.h>
# include <unistd.h>
# define ENABLE_DROP_CACHES 1
using android : : base : : ReadFileToString ;
using android : : base : : WriteStringToFile ;
namespace android {
namespace vold {
// Benchmark currently uses chdir(), which means we can only
// safely run one at a time.
static std : : mutex kBenchmarkLock ;
static const char * kWakeLock = " Benchmark " ;
// Reasonable cards are able to complete the create/run stages
// in under 20 seconds.
constexpr auto kTimeout = 20 s ;
// RAII class for boosting device performance during benchmarks.
class PerformanceBoost {
private :
int orig_prio ;
int orig_ioprio ;
IoSchedClass orig_clazz ;
public :
PerformanceBoost ( ) {
errno = 0 ;
orig_prio = getpriority ( PRIO_PROCESS , 0 ) ;
if ( errno ! = 0 ) {
PLOG ( WARNING ) < < " Failed to getpriority " ;
orig_prio = 0 ;
}
if ( setpriority ( PRIO_PROCESS , 0 , - 10 ) ! = 0 ) {
PLOG ( WARNING ) < < " Failed to setpriority " ;
}
if ( android_get_ioprio ( 0 , & orig_clazz , & orig_ioprio ) ) {
PLOG ( WARNING ) < < " Failed to android_get_ioprio " ;
orig_ioprio = 0 ;
orig_clazz = IoSchedClass_NONE ;
}
if ( android_set_ioprio ( 0 , IoSchedClass_RT , 0 ) ) {
PLOG ( WARNING ) < < " Failed to android_set_ioprio " ;
}
}
~ PerformanceBoost ( ) {
if ( android_set_ioprio ( 0 , orig_clazz , orig_ioprio ) ) {
PLOG ( WARNING ) < < " Failed to android_set_ioprio " ;
}
if ( setpriority ( PRIO_PROCESS , 0 , orig_prio ) ! = 0 ) {
PLOG ( WARNING ) < < " Failed to setpriority " ;
}
}
} ;
static status_t benchmarkInternal ( const std : : string & rootPath ,
const android : : sp < android : : os : : IVoldTaskListener > & listener ,
android : : os : : PersistableBundle * extras ) {
status_t res = 0 ;
auto path = rootPath ;
path + = " /misc " ;
if ( android : : vold : : PrepareDir ( path , 01771 , AID_SYSTEM , AID_MISC ) ) {
@ -56,28 +105,6 @@ static status_t benchmarkInternal(const std::string& rootPath,
return - 1 ;
}
errno = 0 ;
int orig_prio = getpriority ( PRIO_PROCESS , 0 ) ;
if ( errno ! = 0 ) {
PLOG ( ERROR ) < < " Failed to getpriority " ;
return - 1 ;
}
if ( setpriority ( PRIO_PROCESS , 0 , - 10 ) ! = 0 ) {
PLOG ( ERROR ) < < " Failed to setpriority " ;
return - 1 ;
}
IoSchedClass orig_clazz = IoSchedClass_NONE ;
int orig_ioprio = 0 ;
if ( android_get_ioprio ( 0 , & orig_clazz , & orig_ioprio ) ) {
PLOG ( ERROR ) < < " Failed to android_get_ioprio " ;
return - 1 ;
}
if ( android_set_ioprio ( 0 , IoSchedClass_RT , 0 ) ) {
PLOG ( ERROR ) < < " Failed to android_set_ioprio " ;
return - 1 ;
}
char orig_cwd [ PATH_MAX ] ;
if ( getcwd ( orig_cwd , PATH_MAX ) = = NULL ) {
PLOG ( ERROR ) < < " Failed getcwd " ;
@ -90,66 +117,76 @@ static status_t benchmarkInternal(const std::string& rootPath,
sync ( ) ;
LOG( INFO ) < < " Benchmarking " < < path ;
nsecs_t start = systemTime ( SYSTEM_TIME_BOOTTIME ) ;
extras- > putString ( String16 ( " path " ) , String16 ( path . c_str ( ) ) ) ;
extras- > putString ( String16 ( " ident " ) , String16 ( BenchmarkIdent ( ) . c_str ( ) ) ) ;
BenchmarkCreate ( ) ;
sync ( ) ;
nsecs_t create = systemTime ( SYSTEM_TIME_BOOTTIME ) ;
// Always create
{
android : : base : : Timer timer ;
LOG ( INFO ) < < " Creating " < < path ;
res | = BenchmarkCreate ( [ & ] ( int progress ) - > bool {
if ( listener ) {
listener - > onStatus ( progress , * extras ) ;
}
return ( timer . duration ( ) < kTimeout ) ;
} ) ;
sync ( ) ;
if ( res = = OK ) extras - > putLong ( String16 ( " create " ) , timer . duration ( ) . count ( ) ) ;
}
# if ENABLE_DROP_CACHES
LOG ( VERBOSE ) < < " Before drop_caches " ;
if ( ! WriteStringToFile ( " 3 " , " /proc/sys/vm/drop_caches " ) ) {
PLOG ( ERROR ) < < " Failed to drop_caches " ;
// Only drop when we haven't aborted
if ( res = = OK ) {
android : : base : : Timer timer ;
LOG ( VERBOSE ) < < " Before drop_caches " ;
if ( ! WriteStringToFile ( " 3 " , " /proc/sys/vm/drop_caches " ) ) {
PLOG ( ERROR ) < < " Failed to drop_caches " ;
res = - 1 ;
}
LOG ( VERBOSE ) < < " After drop_caches " ;
sync ( ) ;
if ( res = = OK ) extras - > putLong ( String16 ( " drop " ) , timer . duration ( ) . count ( ) ) ;
}
LOG ( VERBOSE ) < < " After drop_caches " ;
# endif
nsecs_t drop = systemTime ( SYSTEM_TIME_BOOTTIME ) ;
BenchmarkRun ( ) ;
sync ( ) ;
nsecs_t run = systemTime ( SYSTEM_TIME_BOOTTIME ) ;
// Only run when we haven't aborted
if ( res = = OK ) {
android : : base : : Timer timer ;
LOG ( INFO ) < < " Running " < < path ;
res | = BenchmarkRun ( [ & ] ( int progress ) - > bool {
if ( listener ) {
listener - > onStatus ( progress , * extras ) ;
}
return ( timer . duration ( ) < kTimeout ) ;
} ) ;
sync ( ) ;
if ( res = = OK ) extras - > putLong ( String16 ( " run " ) , timer . duration ( ) . count ( ) ) ;
}
BenchmarkDestroy ( ) ;
sync ( ) ;
nsecs_t destroy = systemTime ( SYSTEM_TIME_BOOTTIME ) ;
// Always destroy
{
android : : base : : Timer timer ;
LOG ( INFO ) < < " Destroying " < < path ;
res | = BenchmarkDestroy ( ) ;
sync ( ) ;
if ( res = = OK ) extras - > putLong ( String16 ( " destroy " ) , timer . duration ( ) . count ( ) ) ;
}
if ( chdir ( orig_cwd ) ! = 0 ) {
PLOG ( ERROR ) < < " Failed to chdir " ;
return - 1 ;
}
if ( android_set_ioprio ( 0 , orig_clazz , orig_ioprio ) ) {
PLOG ( ERROR ) < < " Failed to android_set_ioprio " ;
}
if ( setpriority ( PRIO_PROCESS , 0 , orig_prio ) ! = 0 ) {
PLOG ( ERROR ) < < " Failed to setpriority " ;
}
nsecs_t create_d = create - start ;
nsecs_t drop_d = drop - create ;
nsecs_t run_d = run - drop ;
nsecs_t destroy_d = destroy - run ;
LOG ( INFO ) < < " create took " < < nanoseconds_to_milliseconds ( create_d ) < < " ms " ;
LOG ( INFO ) < < " drop took " < < nanoseconds_to_milliseconds ( drop_d ) < < " ms " ;
LOG ( INFO ) < < " run took " < < nanoseconds_to_milliseconds ( run_d ) < < " ms " ;
LOG ( INFO ) < < " destroy took " < < nanoseconds_to_milliseconds ( destroy_d ) < < " ms " ;
extras - > putString ( String16 ( " path " ) , String16 ( path . c_str ( ) ) ) ;
extras - > putString ( String16 ( " ident " ) , String16 ( BenchmarkIdent ( ) . c_str ( ) ) ) ;
extras - > putLong ( String16 ( " create " ) , create_d ) ;
extras - > putLong ( String16 ( " drop " ) , drop_d ) ;
extras - > putLong ( String16 ( " run " ) , run_d ) ;
extras - > putLong ( String16 ( " destroy " ) , destroy_d ) ;
return 0 ;
return res ;
}
void Benchmark ( const std : : string & path ,
const android : : sp < android : : os : : IVoldTaskListener > & listener ) {
std : : lock_guard < std : : mutex > lock ( kBenchmarkLock ) ;
acquire_wake_lock ( PARTIAL_WAKE_LOCK , kWakeLock ) ;
PerformanceBoost boost ;
android : : os : : PersistableBundle extras ;
status_t res = benchmarkInternal ( path , & extras ) ;
status_t res = benchmarkInternal ( path , listener , & extras ) ;
if ( listener ) {
listener - > onFinished ( res , extras ) ;
}