1 /*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15 #include "tuningfork/protobuf_util.h"
16 #include "tuningfork/tuningfork_extra.h"
17 #include "swappy/swappy.h"
18 #include "full/tuningfork.pb.h"
19 #include "full/tuningfork_clearcut_log.pb.h"
20 #include "full/dev_tuningfork.pb.h"
21 #include <sstream>
22 #include <jni.h>
23 #include <android/native_window_jni.h>
24
25 #define LOG_TAG "tftestapp"
26 #include "Log.h"
27 #include "Renderer.h"
28
29 using ::com::google::tuningfork::FidelityParams;
30 using ::com::google::tuningfork::Settings;
31 using ::com::google::tuningfork::Annotation;
32 using ::logs::proto::tuningfork::TuningForkLogEvent;
33 using ::logs::proto::tuningfork::TuningForkHistogram;
34
35 namespace proto_tf = com::google::tuningfork;
36 namespace tf = tuningfork;
37 using namespace samples;
38
39 bool swappy_enabled = false;
40
41 namespace {
42
43 constexpr TFInstrumentKey TFTICK_CHOREOGRAPHER = 4;
44
45 struct HistogramSettings {
46 float start, end;
47 int nBuckets;
48 };
TestSettings(Settings::AggregationStrategy::Submission method,int n_ticks,int n_keys,std::vector<int> annotation_size,const std::vector<HistogramSettings> & hists={})49 Settings TestSettings(Settings::AggregationStrategy::Submission method, int n_ticks, int n_keys,
50 std::vector<int> annotation_size,
51 const std::vector<HistogramSettings>& hists = {}) {
52 // Make sure we set all required fields
53 Settings s;
54 s.mutable_aggregation_strategy()->set_method(method);
55 s.mutable_aggregation_strategy()->set_intervalms_or_count(n_ticks);
56 s.mutable_aggregation_strategy()->set_max_instrumentation_keys(n_keys);
57 for(int i=0;i<annotation_size.size();++i)
58 s.mutable_aggregation_strategy()->add_annotation_enum_size(annotation_size[i]);
59 int i=0;
60 for(auto& h: hists) {
61 auto sh = s.add_histograms();
62 sh->set_bucket_min(h.start);
63 sh->set_bucket_max(h.end);
64 sh->set_n_buckets(h.nBuckets);
65 sh->set_instrument_key(i++);
66 }
67 return s;
68 }
69
ReplaceReturns(const std::string & s)70 std::string ReplaceReturns(const std::string& s) {
71 std::string r = s;
72 for (int i=0; i<r.length(); ++i) {
73 if (r[i]=='\n') r[i] = ',';
74 if (r[i]=='\r') r[i] = ' ';
75 }
76 return r;
77 }
78
PrettyPrintTuningForkLogEvent(const TuningForkLogEvent & evt)79 std::string PrettyPrintTuningForkLogEvent(const TuningForkLogEvent& evt) {
80 std::stringstream eventStr;
81 eventStr << "TuningForkLogEvent {\n";
82 if (evt.has_fidelityparams()) {
83 FidelityParams p;
84 p.ParseFromArray(evt.fidelityparams().c_str(), evt.fidelityparams().length());
85 eventStr << " fidelityparams : " << ReplaceReturns(p.DebugString()) << "\n";
86 }
87 for (int i=0; i<evt.histograms_size(); ++i) {
88 auto &h = evt.histograms(i);
89 Annotation ann;
90 ann.ParseFromArray(h.annotation().c_str(), h.annotation().length());
91 bool first = true;
92 eventStr << " histogram {\n";
93 eventStr << " instrument_id : " << h.instrument_id() << "\n";
94 eventStr << " annotation : " << ReplaceReturns(ann.DebugString()) << "\n counts : ";
95 eventStr << "[";
96 for (int j=0; j<h.counts_size(); ++j) {
97 if (first) {
98 first = false;
99 } else {
100 eventStr << ",";
101 }
102 eventStr << h.counts(j);
103 }
104 eventStr << "]\n }\n";
105 }
106 if (evt.has_experiment_id()) {
107 eventStr << " experiment_id : " << evt.experiment_id() << "\n";
108 }
109 if (evt.has_session_id()) {
110 eventStr << " session_id : " << evt.session_id() << "\n";
111 }
112 if (evt.has_device_info()) {
113 eventStr << " device_info : {" << ReplaceReturns(evt.device_info().DebugString()) << "}\n";
114 }
115 if (evt.has_apk_package_name()) {
116 eventStr << " apk_package_name : " << evt.apk_package_name() << "\n";
117 }
118 if (evt.has_apk_version_code()) {
119 eventStr << " apk_version_code : " << evt.apk_version_code() << "\n";
120 }
121 if (evt.has_tuningfork_version()) {
122 eventStr << " tuningfork_version : " << evt.tuningfork_version() << "\n";
123 }
124 eventStr << "}";
125 return eventStr.str();
126 }
SplitAndLog(const std::string & s)127 void SplitAndLog(const std::string& s) {
128 std::istringstream str(s);
129 std::string line;
130 std::stringstream to_log;
131 const int nlines_per_log = 16;
132 int l = nlines_per_log;
133 while (std::getline(str, line, '\n')) {
134 to_log << line << '\n';
135 if(--l<=0) {
136 ALOGI("%s", to_log.str().c_str());
137 l = nlines_per_log;
138 to_log.str("");
139 }
140 }
141 if (to_log.str().length()>0)
142 ALOGI("%s", to_log.str().c_str());
143 }
144
UploadCallback(const CProtobufSerialization * tuningfork_log_event)145 void UploadCallback(const CProtobufSerialization *tuningfork_log_event) {
146 if(tuningfork_log_event) {
147 TuningForkLogEvent evt;
148 evt.ParseFromArray(tuningfork_log_event->bytes, tuningfork_log_event->size);
149 auto pp = PrettyPrintTuningForkLogEvent(evt);
150 SplitAndLog(pp);
151 }
152 }
153
154 static int sLevel = proto_tf::LEVEL_1;
155 extern "C"
SetAnnotations()156 void SetAnnotations() {
157 if(proto_tf::Level_IsValid(sLevel)) {
158 Annotation a;
159 a.set_level((proto_tf::Level)sLevel);
160 auto next_level = sLevel + 1;
161 a.set_next_level((proto_tf::Level)(next_level>proto_tf::Level_MAX?1:next_level));
162 auto ser = tf::CProtobufSerialization_Alloc(a);
163 TuningFork_setCurrentAnnotation(&ser);
164 tf::CProtobufSerialization_Free(&ser);
165 }
166 }
167
SetFidelityParams(const CProtobufSerialization * params)168 void SetFidelityParams(const CProtobufSerialization* params) {
169 FidelityParams p;
170 // Set default values
171 p.set_num_spheres(20);
172 p.set_tesselation_percent(50);
173 std::vector<uint8_t> params_ser(params->bytes, params->bytes + params->size);
174 tf::Deserialize(params_ser, p);
175 std::string s = p.DebugString();
176 ALOGI("Using FidelityParams: %s", ReplaceReturns(s).c_str());
177 int nSpheres = p.num_spheres();
178 int tesselation = p.tesselation_percent();
179 Renderer::getInstance()->setQuality(nSpheres, tesselation);
180 }
181
182 } // anonymous namespace
183
184 extern "C" {
185
186 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_initTuningFork(JNIEnv * env,jobject activity)187 Java_com_google_tuningfork_TFTestActivity_initTuningFork(JNIEnv *env, jobject activity) {
188 Swappy_init(env, activity);
189 swappy_enabled = Swappy_isEnabled();
190 if (swappy_enabled) {
191 int defaultFPIndex = 3; // i.e. dev_tuningfork_fidelityparams_3.bin
192 int initialTimeoutMs = 1000;
193 int ultimateTimeoutMs = 100000;
194 TFErrorCode c = TuningFork_initFromAssetsWithSwappy(env, activity, "libnative-lib.so",
195 SetAnnotations, defaultFPIndex,
196 SetFidelityParams,
197 initialTimeoutMs, ultimateTimeoutMs);
198 if (c==TFERROR_OK) {
199 TuningFork_setUploadCallback(UploadCallback);
200 SetAnnotations();
201 } else {
202 ALOGW("Error initializing TuningFork: %d", c);
203 }
204 } else {
205 ALOGW("Couldn't enable Swappy.");
206 CProtobufSerialization settings = {};
207 TuningFork_findSettingsInAPK(env, activity, &settings);
208 TuningFork_init(&settings, env, activity);
209 tuningfork::CProtobufSerialization_Free(&settings);
210 int fp_count;
211 TuningFork_findFidelityParamsInAPK(env, activity, NULL, &fp_count);
212 CProtobufSerialization fps = {};
213 std::vector<CProtobufSerialization> defaultFPs(fp_count);
214 TuningFork_findFidelityParamsInAPK(env, activity, defaultFPs.data(), &fp_count);
215 CProtobufSerialization* defaultFP = &defaultFPs[fp_count/2-1]; // Middle settings level
216 if (TuningFork_getFidelityParameters(defaultFP, &fps, 1000)) {
217 SetFidelityParams(&fps);
218 tuningfork::CProtobufSerialization_Free(&fps);
219 }
220 else {
221 SetFidelityParams(defaultFP);
222 }
223 for(auto& a: defaultFPs) {
224 tuningfork::CProtobufSerialization_Free(&a);
225 }
226 TuningFork_setUploadCallback(UploadCallback);
227 SetAnnotations();
228 }
229 }
230
231 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_onChoreographer(JNIEnv *,jclass clz,jlong)232 Java_com_google_tuningfork_TFTestActivity_onChoreographer(JNIEnv */*env*/, jclass clz, jlong /*frameTimeNanos*/) {
233 TuningFork_frameTick(TFTICK_CHOREOGRAPHER);
234 // After 600 ticks, switch to the next level
235 static int tick_count = 0;
236 ++tick_count;
237 if(tick_count>=600) {
238 ++sLevel;
239 if(sLevel>proto_tf::Level_MAX) sLevel = proto_tf::LEVEL_1;
240 SetAnnotations();
241 tick_count = 0;
242 }
243 }
244 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_resize(JNIEnv * env,jclass,jobject surface,jint width,jint height)245 Java_com_google_tuningfork_TFTestActivity_resize(JNIEnv *env, jclass /*clz*/, jobject surface, jint width, jint height) {
246 ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
247 Renderer::getInstance()->setWindow(window,
248 static_cast<int32_t>(width),
249 static_cast<int32_t>(height));
250 }
251 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_clearSurface(JNIEnv *,jclass)252 Java_com_google_tuningfork_TFTestActivity_clearSurface(JNIEnv */*env*/, jclass /*clz*/ ) {
253 Renderer::getInstance()->setWindow(nullptr, 0, 0);
254 }
255 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_start(JNIEnv *,jclass)256 Java_com_google_tuningfork_TFTestActivity_start(JNIEnv */*env*/, jclass /*clz*/ ) {
257 Renderer::getInstance()->start();
258 }
259 JNIEXPORT void JNICALL
Java_com_google_tuningfork_TFTestActivity_stop(JNIEnv *,jclass)260 Java_com_google_tuningfork_TFTestActivity_stop(JNIEnv */*env*/, jclass /*clz*/ ) {
261 Renderer::getInstance()->stop();
262 }
263
264 }
265