• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "GpuCalculationHelpers.h"
18 
19 using std::literals::chrono_literals::operator""ns;
20 using std::chrono::duration;
21 using std::chrono::duration_cast;
22 using std::chrono::nanoseconds;
23 
24 namespace aidl {
25 namespace google {
26 namespace hardware {
27 namespace power {
28 namespace impl {
29 namespace pixel {
30 
31 // until std::lerp is available...
32 template <typename R, typename P>
lerp(duration<R,P> a,duration<R,P> b,float t)33 duration<R, P> lerp(duration<R, P> a, duration<R, P> b, float t) {
34     auto const fa = duration_cast<duration<float, std::nano>>(a);
35     auto const fb = duration_cast<duration<float, std::nano>>(b);
36     return duration_cast<duration<R, P>>(fa + (fb - fa) * t);
37 }
38 
39 // In the event that the client reports that the GPU + CPU time is less than
40 // the total time, expand both CPU and GPU timings so that this constraint
41 // holds true.
sanitize_timings(nanoseconds total,nanoseconds cpu,nanoseconds gpu)42 nanoseconds sanitize_timings(nanoseconds total, nanoseconds cpu, nanoseconds gpu) {
43     auto const accounted_portion = cpu + gpu;
44     auto const unaccounted_portion = total - accounted_portion;
45     if (unaccounted_portion > 0ns) {
46         auto const cpu_portion = duration_cast<duration<float, std::nano>>(cpu) / accounted_portion;
47         gpu = lerp(gpu, gpu + unaccounted_portion, (1.0 - cpu_portion));
48     }
49     return gpu;
50 }
51 
subtotal_timings_invalid(WorkDuration const & observation)52 inline bool subtotal_timings_invalid(WorkDuration const &observation) {
53     return observation.durationNanos < observation.gpuDurationNanos ||
54            observation.durationNanos < observation.cpuDurationNanos;
55 }
56 
calculate_capacity(WorkDuration observation,nanoseconds target,Frequency gpu_frequency)57 Cycles calculate_capacity(WorkDuration observation, nanoseconds target, Frequency gpu_frequency) {
58     auto const total = nanoseconds(observation.durationNanos);
59 
60     auto const overrun = duration_cast<duration<float, std::nano>>(total - target);
61     if (overrun < 0ns || subtotal_timings_invalid(observation)) {
62         return Cycles(0);
63     }
64 
65     auto const gpu = sanitize_timings(total, nanoseconds(observation.cpuDurationNanos),
66                                       nanoseconds(observation.gpuDurationNanos));
67 
68     auto const gpu_time_attribution_pct = gpu_time_attribution(total, gpu);
69     auto const gpu_delta = overrun * gpu_time_attribution_pct;
70     return gpu_frequency * gpu_delta;
71 }
72 
73 }  // namespace pixel
74 }  // namespace impl
75 }  // namespace power
76 }  // namespace hardware
77 }  // namespace google
78 }  // namespace aidl
79