1// Copyright (c) 2018 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#if defined(SPIRV_TIMER_ENABLED)
16
17#include "source/util/timer.h"
18
19#include <sys/resource.h>
20#include <sys/time.h>
21#include <iomanip>
22#include <iostream>
23#include <string>
24
25namespace spvtools {
26namespace utils {
27
28void PrintTimerDescription(std::ostream* out, bool measure_mem_usage) {
29 if (out) {
30 *out << std::setw(30) << "PASS name" << std::setw(12) << "CPU time"
31 << std::setw(12) << "WALL time" << std::setw(12) << "USR time"
32 << std::setw(12) << "SYS time";
33 if (measure_mem_usage) {
34 *out << std::setw(12) << "RSS delta" << std::setw(16) << "PGFault delta";
35 }
36 *out << std::endl;
37 }
38}
39
40// Do not change the order of invoking system calls. We want to make CPU/Wall
41// time correct as much as possible. Calling functions to get CPU/Wall time must
42// closely surround the target code of measuring.
43void Timer::Start() {
44 if (report_stream_) {
45 if (getrusage(RUSAGE_SELF, &usage_before_) == -1)
46 usage_status_ |= kGetrusageFailed;
47 if (clock_gettime(CLOCK_MONOTONIC, &wall_before_) == -1)
48 usage_status_ |= kClockGettimeWalltimeFailed;
49 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_before_) == -1)
50 usage_status_ |= kClockGettimeCPUtimeFailed;
51 }
52}
53
54// The order of invoking system calls is important with the same reason as
55// Timer::Start().
56void Timer::Stop() {
57 if (report_stream_ && usage_status_ == kSucceeded) {
58 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_after_) == -1)
59 usage_status_ |= kClockGettimeCPUtimeFailed;
60 if (clock_gettime(CLOCK_MONOTONIC, &wall_after_) == -1)
61 usage_status_ |= kClockGettimeWalltimeFailed;
62 if (getrusage(RUSAGE_SELF, &usage_after_) == -1)
63 usage_status_ = kGetrusageFailed;
64 }
65}
66
67void Timer::Report(const char* tag) {
68 if (!report_stream_) return;
69
70 report_stream_->precision(2);
71 *report_stream_ << std::fixed << std::setw(30) << tag;
72
73 if (usage_status_ & kClockGettimeCPUtimeFailed)
74 *report_stream_ << std::setw(12) << "Failed";
75 else
76 *report_stream_ << std::setw(12) << CPUTime();
77
78 if (usage_status_ & kClockGettimeWalltimeFailed)
79 *report_stream_ << std::setw(12) << "Failed";
80 else
81 *report_stream_ << std::setw(12) << WallTime();
82
83 if (usage_status_ & kGetrusageFailed) {
84 *report_stream_ << std::setw(12) << "Failed" << std::setw(12) << "Failed";
85 if (measure_mem_usage_) {
86 *report_stream_ << std::setw(12) << "Failed" << std::setw(12) << "Failed";
87 }
88 } else {
89 *report_stream_ << std::setw(12) << UserTime() << std::setw(12)
90 << SystemTime();
91 if (measure_mem_usage_) {
92 *report_stream_ << std::fixed << std::setw(12) << RSS() << std::setw(16)
93 << PageFault();
94 }
95 }
96 *report_stream_ << std::endl;
97}
98
99} // namespace utils
100} // namespace spvtools
101
102#endif // defined(SPIRV_TIMER_ENABLED)
103